核心要点
NodeList.js 作为 jQuery 的 DOM 操作替代方案,提供类似的功能,但体积更小(压缩后 4k),并利用了原生浏览器 API 的改进。
与 jQuery 不同,NodeList.js 将节点数组视为单个节点,从而实现更简洁的代码和更轻松的 NodeList 对象操作。
NodeList.js 包含用于设置和获取属性、调用特定于元素的方法以及访问 NodeList 中节点的特殊方法,以及等同于 jQuery 的 prevObject
属性的 owner
属性。
NodeList.js 与特定版本以后的主流浏览器兼容(Firefox 6 、Safari 5.0.5 、Chrome 6 、IE 9 、Opera 11.6 ),并自动更新以包含浏览器新增的方法/属性。
p.tip { background-color: rgba(128,128,128,0.05); border-top-right-radius: 5px; border-bottom-right-radius: 5px; padding: 15px 20px; border-left: 10px solid rgba(128,128,128,0.075); }
近年来,jQuery 已成为 Web 上事实上的 JavaScript 库。它消除了许多跨浏览器的不一致性,并为客户端脚本添加了一层受欢迎的语法糖。它抽象化处理的主要痛点之一是 DOM 操作,但自 jQuery 问世以来,原生浏览器 API 已得到显著改进,“你可能不需要 jQuery” 的理念开始流行起来。
原因如下:
addEventListener
代替 attachEvent
。问题在于,与 jQuery 相比,使用原生(或纯)JavaScript 进行 DOM 操作可能很麻烦。这是因为您必须编写更多冗余代码,并处理浏览器无用的 NodeList。
首先,让我们看看 MDN 对 NodeList 的定义:
NodeList 对象是节点的集合,例如 Node.childNodes
和 document.querySelectorAll
方法返回的那些节点。
有时还存在动态 NodeList(这可能会令人困惑):
在某些情况下,NodeList 是动态集合,这意味着 DOM 中的更改会反映在集合中。例如,Node.childNodes
是动态的。
这可能是一个问题,因为您无法分辨哪些是动态的,哪些是静态的。除非您从 NodeList 中移除每个节点,然后检查 NodeList 是否为空。如果为空,则表示您拥有一个动态 NodeList(这只是一个坏主意)。
此外,浏览器没有提供任何有用的方法来操作这些 NodeList 对象。
例如,不幸的是,无法使用 forEach
循环遍历节点:
var nodes = document.querySelectorAll('div'); nodes.forEach(function(node) { // do something }); // 错误:nodes.forEach 不是函数
因此,您必须执行以下操作:
var nodes = document.querySelectorAll('div'); for(var i = 0, l = nodes.length; i < l; i++) { // do something with nodes[i] }
或者甚至只能使用“hack”:
[].forEach.call(document.querySelectorAll('div'), function(node) { // do something });
浏览器的原生 NodeList 只有一个方法:item
。它通过索引从 NodeList 返回一个节点。当我们可以像使用数组一样访问该节点(使用 array[index]
)时,它完全没用:
var nodes = document.querySelectorAll('div'); nodes.item(0) === nodes[0]; // true
这就是 NodeList.js 的用武之地——使使用浏览器原生 API 操作 DOM 变得像使用 jQuery 一样容易,但仅需 4k 压缩大小。
我创建 NodeList.js 是因为我一直使用原生 DOM API,但希望使它们更简洁,从而减少编写代码时的许多冗余(例如 for 循环)。
NodeList.js 是原生 DOM API 的一个包装器,它允许您操作节点数组(即我的 NodeList),就好像它是一个单个节点一样。这为您提供了比浏览器原生 NodeList 对象更多的功能。
如果您觉得这不错,请从官方 GitHub 存储库获取 NodeList.js 的副本,并继续阅读本教程的其余部分。
选择 DOM 节点很简单:
$$(selector);
// 返回我的 NodeList
此方法在后台使用 querySelectorAll(selector)
。
很高兴您提出这个问题。让我们将原生 JS、jQuery 和 NodeList.js 进行比较。
假设我们有三个按钮:
让我们将每个按钮的文本更改为“点击我”:
var buttons = document.querySelectorAll('button'); // 返回浏览器无用的 NodeList for(var i = 0, l = buttons.length; i < l; i++) { buttons[i].textContent = 'Click Me'; }
$('button').text('Click Me');
$$('button').textContent = 'Click Me';
在这里,我们看到 NodeList.js 可以有效地将 NodeList 视为单个节点。也就是说,我们引用了一个 NodeList,并将它的 textContent
属性设置为“点击我”。然后,NodeList.js 将对 NodeList 中的每个节点执行此操作。很巧妙,对吧?
如果我们想要方法链(类似于 jQuery),我们会执行以下操作,这将返回对 NodeList 的引用:
$$('button').set('textContent', 'Click Me');
现在,让我们向每个按钮添加一个点击事件监听器:
var buttons = document.querySelectorAll('button'); // 返回浏览器无用的 NodeList for(var i = 0, l = buttons.length; i < l; i++) { buttons[i].addEventListener('click', function() { this.classList.add('clicked'); }); }
$('button').on('click', function() { $(this).addClass('click'); // 或将 jQuery 与原生混合使用 `classList`: this.classList.add('clicked'); });
$$('button').addEventListener('click', function() { this.classList.add('clicked'); });
好的,所以 jQuery 的 on
方法相当不错。我的库使用浏览器的原生 DOM API(因此是 addEventListener
),但这并不会阻止我们为该方法创建别名:
$$.NL.on = $$.NL.addEventListener; $$('button').on('click', function() { this.classList.add('clicked'); });
不错!这演示了我们添加自己方法的方式:
var nodes = document.querySelectorAll('div'); nodes.forEach(function(node) { // do something }); // 错误:nodes.forEach 不是函数
NodeList.js 确实继承自 Array.prototype
,但不是直接继承,因为某些方法已更改,因此使用它们与 NodeList(节点数组)一起使用是有意义的。
push
和 unshift
例如:push
和 unshift
方法只能将节点作为参数,否则会抛出错误:
var nodes = document.querySelectorAll('div'); for(var i = 0, l = nodes.length; i < l; i++) { // do something with nodes[i] }
因此,push
和 unshift
都返回 NodeList 以允许方法链,这意味着它与 JavaScript 的原生 Array#push
或 Array#unshift
方法不同,后者接受任何内容并返回数组的新长度。如果我们确实想要 NodeList 的长度,我们只需使用 length
属性。
这两个方法,就像 JavaScript 的原生数组方法一样,都会更改 NodeList。
concat
concat
方法将接受以下内容作为参数:
[].forEach.call(document.querySelectorAll('div'), function(node) { // do something });
concat
是一个递归方法,因此这些数组可以像我们希望的那样深,并且会被展平。但是,如果传递的数组中的任何元素不是节点、NodeList 或 HTMLCollection,它将抛出错误。
concat
返回一个新的 NodeList,就像 javascript 的 Array#concat
方法一样。
pop
、shift
、map
、slice
、filter
pop
和 shift
方法都可以采用可选参数,说明要从 NodeList 中弹出或移位多少个节点。与 JavaScript 的原生 Array#pop
或 Array#shift
不同,后者总是弹出或移位数组中的一个元素,而不管传递什么作为参数。
如果每个映射值都是一个节点,map
方法将返回一个 NodeList;如果不是,则返回映射值的数组。
slice
和 filter
方法的作用与在真实数组中的作用一样,但会返回一个 NodeList。
由于 NodeList.js 没有直接继承自 Array.prototype
,因此如果在加载 NodeList.js 后向 Array.prototype
添加方法,则不会继承该方法。
您可以在此处查看 NodeList.js 的其余数组方法。
NodeList.js 有四个独特的方法,以及一个名为 owner
的属性,它等同于 jQuery 的 prevObject
属性。
get
和 set
方法:某些元素具有特定于该类型元素的属性(例如,锚标记上的 href
属性)。这就是为什么 $$('a').href
将返回未定义的原因——因为它不是 NodeList 中每个元素都继承的属性。这就是我们如何使用 get
方法访问这些属性的方法:
var nodes = document.querySelectorAll('div'); nodes.forEach(function(node) { // do something }); // 错误:nodes.forEach 不是函数
set
方法可用于为每个元素设置这些属性:
var nodes = document.querySelectorAll('div'); for(var i = 0, l = nodes.length; i < l; i++) { // do something with nodes[i] }
set
还返回 NodeList 以允许方法链。我们可以在 textContent
等方面使用它(两者都等效):
[].forEach.call(document.querySelectorAll('div'), function(node) { // do something });
我们还可以在一次调用中设置多个属性:
var nodes = document.querySelectorAll('div'); nodes.item(0) === nodes[0]; // true
以上所有操作都可以使用任意属性完成,例如 style
:
var buttons = document.querySelectorAll('button'); // 返回浏览器无用的 NodeList for(var i = 0, l = buttons.length; i < l; i++) { buttons[i].textContent = 'Click Me'; }
call
方法call
方法允许您调用特定于元素的方法(例如,视频元素上的 pause
):
$('button').text('Click Me');
item
方法item
方法等同于 jQuery 的 eq
方法。它返回一个 NodeList,其中只包含传递索引的节点:
$$('button').textContent = 'Click Me';
owner
属性owner
属性等同于 jQuery 的 prevObject
。
$$('button').set('textContent', 'Click Me');
btns.style
返回样式数组,而 owner
将返回 style
所映射的 NodeList。
我的库与所有主要的新浏览器兼容,如下所述。
浏览器 版本
现在我们终于可以使用有用的 NodeList 对象了!
对于大约 4k 的压缩大小,您可以获得上述所有功能以及更多功能,您可以在 NodeList.js 的 GitHub 存储库中了解所有这些功能。
由于 NodeList.js 使用浏览器作为依赖项,因此无需进行任何升级。每当浏览器向 DOM 元素添加新方法/属性时,您都可以通过 NodeList.js 自动使用这些方法/属性。所有这一切都意味着您唯一需要担心的弃用是浏览器删除的方法。这些通常是使用率非常低的方法,因为我们不能破坏 Web。
那么您怎么看?您会考虑使用这个库吗?是否缺少任何重要功能?我很乐意在下面的评论中听到您的意见。
NodeList 和 HTMLCollection 都是节点集合。它们之间的主要区别在于 NodeList 可以包含任何节点类型,而 HTMLCollection 是元素节点的集合。HTMLCollection 也是动态的,这意味着当文档结构发生更改时,它会自动更新。另一方面,NodeList 是静态的,不会更新以反映文档中的更改。
您可以使用 Array.from()
方法或展开运算符将 NodeList 转换为数组。以下是如何操作:
var nodes = document.querySelectorAll('div'); nodes.forEach(function(node) { // do something }); // 错误:nodes.forEach 不是函数
jQuery 的链式机制通过在进行更改之前存储之前的对象来工作。这允许您使用 .end()
方法恢复到之前的状态。如果您想获取实际的 DOM 元素,可以使用 .get()
方法或数组表示法。
您可以使用 for 循环、for...of 循环或 forEach()
方法循环遍历 NodeList。这是一个使用 for 循环的示例:
var nodes = document.querySelectorAll('div'); for(var i = 0, l = nodes.length; i < l; i++) { // do something with nodes[i] }
jQuery 中的 .prev()
方法用于选择所选元素的紧邻前一个同级元素。如果提供了选择器,则只有在匹配该选择器时才会检索前一个同级元素。
虽然 jQuery 在发布时是一个改变游戏规则的东西,但现代 JavaScript 生态系统已经发生了显着变化。许多使 jQuery 受欢迎的功能现在都内置于 JavaScript 本身。但是,jQuery 仍然被广泛使用和维护,它可能是某些项目的良好选择。
您可以使用数组表示法或 item()
方法从 NodeList 中选择特定节点。以下是如何操作:
[].forEach.call(document.querySelectorAll('div'), function(node) { // do something });
NodeList 不是数组,因此它没有像 map、filter 和 reduce 这样的方法。但是,您可以将 NodeList 转换为数组,然后使用这些方法。
querySelector
返回文档中与指定的 CSS 选择器匹配的第一个元素,而 querySelectorAll
返回与 CSS 选择器匹配的所有元素的 NodeList。
您可以通过检查其 length
属性来检查 NodeList 是否为空。如果长度为 0,则 NodeList 为空。以下是如何操作:
var nodes = document.querySelectorAll('div'); nodes.item(0) === nodes[0]; // true
以上是失去jQuery膨胀的详细内容。更多信息请关注PHP中文网其他相关文章!