javascript - 如何将 HTML 元素数组转换为 NodeList?
问题描述
我们正在尝试document.querySelectorAll()
用我们自己的函数替换,我们不想检查所有当前的使用,也许不得不重构这些。我们试图返回一个 NodeList,但这似乎是不可能的,因为没有明显的方法来创建它。
所以我们试图返回一个 HTML 元素数组,使它看起来像一个 NodeList。复制 NodeList 的接口相对容易,但问题是:如何重载方括号 ([]) 运算符? 显然在 JavaScript 中是不可能的。
解决方案
由于NodeList
对象是快照(它们不会像 anHTMLCollection
那样跟踪 DOM 的内容),其内容NodeList
是静态的,这使得支持[]
索引变得容易:只需分配给索引。数组只是具有几个附加行为的对象(一个动态length
属性,length
在您分配时进行调整 via []
,当然还有Array.prototype
)。创造工作的东西就是创造array[0]
工作的东西anyObject["property name"]
。
要制作看起来像 的东西,NodeList
我认为您需要:
- 放入
NodeList.prototype
它的原型链,这样就instanceof
可以了 - 支持
item
- 支持索引(在这种情况下,只需分配给这些属性)
- 支持
length
作为具有 getter 而没有 setter 的访问器,而不是不可写的数据属性(以防万一)
例如(见评论):
// Constructor
function PseudoNodeList(arrayLike) {
const length = arrayLike.length;
// Define `length` -- slight difference with `NodeList` here, this is
// defined on the object itself, but `NodeList` has it on the prototype
Object.defineProperty(this, "length", {
get() {
return length;
},
enumerable: true, // Oddly, it is on `NodeList.prototype`
configurable: true,
});
// Copy the indexed entries
Object.assign(this, Array.from(arrayLike));
// (Instead of the statement above, you could use a `for` loop, which
// would likely be faster -- you did mention performance)
}
// Make `instanceof` work, and inherit the implementations of
// [Symbol.iterator] and other methods -- though you'll want to test that
// Safari and Firefox are okay with inheriting them, I only checked on
// Chromium-based browsers (Chromium, Chrome, Brave, Edge, Opera I think).
// They may be more picky about `this`.
PseudoNodeList.prototype = Object.create(NodeList.prototype);
// Fix `constructor` property
PseudoNodeList.prototype.constructor = PseudoNodeList;
// Add item method
Object.defineProperty(PseudoNodeList.prototype, "item", {
value(index) {
if (index < 0 || index >= this.length) {
return null;
}
return this[index];
},
enumerable: true, // Oddly, it is on `NodeList.prototype`
configurable: true,
});
现场示例:
// Constructor
function PseudoNodeList(arrayLike) {
const length = arrayLike.length;
// Define `length` -- slight difference with `NodeList` here, this is
// defined on the object itself, but `NodeList` has it on the prototype
Object.defineProperty(this, "length", {
get() {
return length;
},
enumerable: true, // Oddly, it is on `NodeList.prototype`
configurable: true,
});
// Copy the indexed entries
Object.assign(this, Array.from(arrayLike));
// (Instead of the statement above, you could use a `for` loop, which
// would likely be faster -- you did mention performance)
}
// Make `instanceof` work, and inherit the implementations of
// [Symbol.iterator] and other methods -- though you'll want to test that
// Safari and Firefox are okay with inheriting them, I only checked on
// Chromium-based browsers (Chromium, Chrome, Brave, Edge, Opera I think).
// They may be more picky about `this`.
PseudoNodeList.prototype = Object.create(NodeList.prototype);
// Fix `constructor` property
PseudoNodeList.prototype.constructor = PseudoNodeList;
// Add item method
Object.defineProperty(PseudoNodeList.prototype, "item", {
value(index) {
if (index < 0 || index >= this.length) {
return null;
}
return this[index];
},
enumerable: true, // Oddly, it is on `NodeList.prototype`
configurable: true,
});
// ======= Using it:
const p = new PseudoNodeList(
document.querySelectorAll(".example")
);
console.log(`p instanceof NodeList? ${p instanceof NodeList}`);
console.log(`p.length = ${p.length}`);
console.log(`p.keys():`, [...p.keys()]);
console.log(`p.values():`, [...p.values()]);
console.log(`p.entries():`, [...p.entries()]);
// Turn all of them green via iteration
for (const el of p) {
el.style.color = "green";
}
// Use `item` method to make the first match `font-size: 20px`
p.item(0).style.fontSize = "20px";
// Use indexed property to make the first match `font-style: italic`
p[1].style.fontStyle = "italic";
<div>one</div>
<div class="example">two</div>
<div>one</div>
<div class="example">three</div>
我没有采用子类化的方法Array
(这肯定是另一种方法),因为我不想隐藏所有没有的数组方法NodeList
。
如果您想使[]
索引动态化(您不需要NodeList
替身,因为它们也是静态的),您可以使用Proxy
.
推荐阅读
- c++ - 如何将输入字符串流与分隔字符串而不是空格的符号一起使用?
- css - CSS背景上的多个圆圈
- python - 从 JSON Discord PY 中删除所有用户信息
- css - Angular Material Table - CSS 在文本换行时让标题左对齐
- django - Django Rest Framework 视图集 - 基于用户名问题的 ForeignKey 过滤器
- java - 从用逗号分隔的文件中读取整数到二维数组中
- spring - Spring-tx:仅当最外层方法未捕获异常时才回滚
- git - 应用存储是否涉及三向合并,或者只是将存储修补到当前工作树?
- javascript - 将数据从数组传递到数组
- php - PHP:如何使用 whereIn 子句根据多个 ID 更新一列