创建一个函数来获取像 jquery 和纯 javascript 这样的选择器

Create a function to get selectors like jquery does with pure javascript

我厌倦了将 jquery 包含在简单的项目中,但我已经习惯使用它,并且我正在努力摆脱对它的依赖。我正在尝试创建一个函数,该函数将提供与获取 类 和标签等选择器相同的感觉。示例:$('selector').innerHTML = ".something";。我只是像这样一个接一个地循环:

var classElements = document.querySelectorAll('.something');
for (var i = classElements.length - 1; i >= 0; i--) {
   classElements[i].innerHTML = "This Is A Div";
} 

但我想创建一个函数,我可以在其中循环选择器,而不必为我想要查找的所有内容编写 for 循环。所以我可以像上面那样写 $('.something').innerHTML = "something";

到目前为止,这就是我所拥有的,但它只会获得每个选择器的第一个,而不会获得所有选择器。毋庸置疑,我非常困惑,而且我对这个主题的阅读越多,我就越困惑。我想知道是否有人可以指出我的想法存在缺陷的正确方向,或者解释 jquery 是如何做到这一点的。这是我的代码:

window.getElements = function(selector) {
    var selectors = document.querySelectorAll(selector);
    for (var i = selectors.length - 1; i >= 0; i--) {
        var elements = selectors[i];
    }
    return elements;
};

getElements(".something").innerHTML = "something";

这是一个fiddleFiddle

JQuery 的选择器部分称为 Sizzle。它具有您需要的所有功能,但不包含 JQuery.

的其他部分

如果你想了解更多关于它背后的javascript,我建议你看看Sizzle的源文件。

getElements(".something").innerHTML = "something";

这不起作用,因为你的函数 获取 和 returns 所有元素,这是一个 NodeList,但它不会自动应用集合中每个元素的方法,如 jQuery 所做的那样。为此,您必须将元素转换为数组,并使用循环或其他函数实际调用每个元素上的函数。

编辑:明确地说,您不能只在 NodeList 上调用 NodeList.innerHTML = '',因为 innerHTML 应用于一个元素。 jQuery 在内部负责 BOTH 元素收集,以及 applying 方法。

编辑#2:在更仔细地检查你的功能后,我意识到还有其他问题,但我上面写的仍然是你想要 spring.

您可以使用类似这样的方法来获取元素吗?:

function getElements(elements) {
    return [...querySelectorAll(elements)]
}

但是在 case-by-case 的基础上,在节点上应用函数将更具选择性,因为其中许多函数的应用方式不同。

以下是您的操作方法。我已经完成了你所要求的,它允许你使用所有本机功能而不是围绕它的硬币包装器。 jQuery returns 它自己的 api 作用于选择器。我所做的是创建一个选择器,它允许您对它找到的每个元素进行操作

window.getElements = function(selector,cb) {
    var selectors = document.querySelectorAll(selector);
    [].forEach.call(selectors, cb);
};

getElements(".something", function(el){el.innerHTML = "ha"});

getElements("#one", function(el){el.style.background = "red" });

它获取找到的 dom 列表,将其转换为数组,然后在您传递本机代码的地方调用您传递的函数

这是一个fiddle

https://jsfiddle.net/y52f4wh8/5/

Jquery 工作方式不同:

window.jquery = function(selector,cb) {
 var selectors = document.querySelectorAll(selector);
    
    function command(cb) {
    [].forEach.call(selectors, cb);
 };
    // Here we return our own api that uses the command function to act on
    // our selected list.
    return {
     html: function(str){
      command(function(el){
       el.innerHTML=str;
      });
      
     },
     bg: function(color){
      command(function(el){
       el.style.background = color; 
      });
     }
    }
};
// The jquery way!
jquery(".something").html("ha");

jQuery 本质上是 NodeList 的包装对象,它为 DOM 操作添加了更多功能。如果你想创建你自己的包装器对象来定义所有 Element API 的批量版本的函数,你可以自由地这样做,但是你也可以使用 jQuery 或一些导数。

如果你想要一个非常轻量级的代理对象来对 DOM 元素进行批量操作,ES6 中的 Proxy 对象可以使这很容易做到,但不支持 IE .

const $ = function(selector) {
  const nodeList = document.querySelectorAll(selector);
  return new Proxy(nodeList, {
    set: function(target, property, value) {
      for (let i = 0; i < target.length; i++) {
        target[i][property] = value;
      }
    },
    get: function(target, property) {
      return target[0] && target[0][property];
    }
  });
};

console.log($('p').innerHTML);
$('p').innerHTML = 'Bulk assignement!';
<p>A B C</p>
<p>1 2 3</p>
<p>Do Re Mi</p>

最好避免的一种方法是在 NodeList 上为 innerHTML 定义 setter。

Object.defineProperty(NodeList.prototype, 'innerHTML', {
  set(text) {
    [...this].forEach(elt => elt.innerHTML = text);
  }
});

const $ = selector => document.querySelectorAll(selector);

$('.foo').innerHTML = "it works";
<div class="foo"></div>
<div class="foo"></div>