在 JavaScript 中从单个节点创建节点列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13351966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 18:31:42  来源:igfitidea点击:

Create node list from a single node in JavaScript

javascriptnodesnodelist

提问by Randy Hall

This is one of those it seems so simple, but I cannot come up with a good way to go about it.

这是其中之一,它看起来很简单,但我想不出一个好的方法来解决它。

I have a node, maybe nodelist = document.getElementById("mydiv");- I need to normalize this to a node list. And not an array either: an actual, bona-fide nodeListobject.

我有一个节点,也许nodelist = document.getElementById("mydiv");- 我需要将其标准化为节点列表。也不是数组:一个实际的、真正的nodeList对象。

Notnodelist = [document.getElementById("mydiv")];

不是nodelist = [document.getElementById("mydiv")];

No libraries, please.

请不要图书馆。

采纳答案by Paul S.

Reviving this because I recently remembered something about JavaScript. This depends on how the NodeListis being checked, but..

重温这个是因为我最近想起了一些关于JavaScript 的事情。这取决于如何检查NodeList,但是..

var singleNode = (function () {
    // make an empty node list to inherit from
    var nodelist = document.createDocumentFragment().childNodes;
    // return a function to create object formed as desired
    return function (node) {
        return Object.create(nodelist, {
            '0': {value: node, enumerable: true},
            'length': {value: 1},
            'item': {
                "value": function (i) {
                    return this[+i || 0];
                }, 
                enumerable: true
            }
        }); // return an object pretending to be a NodeList
    };
}());

Now, if you do

现在,如果你这样做

var list = singleNode(document.body); // for example

list instanceof NodeList; // true
list.constructor === NodeList; // true

and listhas properties length1and 0as your node, as well as anything inherited from NodeList.

list具有属性length10作为您的节点,以及从NodeList继承的任何内容。

If you can't use Object.create, you could do the same except as a constructor with prototype nodelistand set this['0'] = node;, this['length'] = 1;and create with new.

如果你不能使用Object.create,你可以做同样的事情,除了使用原型nodelist和设置的构造函数this['0'] = node;this['length'] = 1;并用new.

回答by Paul S.

Take any element already referenced in JavaScript, give it an attribute we can find using a selector, find it as a list, remove the attribute, return the list.

取任何已在 JavaScript 中引用的元素,给它一个我们可以使用选择器找到的属性,将其作为列表查找,删除该属性,返回列表。

function toNodeList(elm){
    var list;
    elm.setAttribute('wrapNodeList','');
    list = document.querySelectorAll('[wrapNodeList]');
    elm.removeAttribute('wrapNodeList');
    return list;
}

Extended from bfavaretto's answer.

扩展自 bfavaretto 的回答。



function toNodeList(elm, context){
    var list, df;
    context = context // context provided
           || elm.parentNode; // element's parent
    if(!context && elm.ownerDocument){ // is part of a document
        if(elm === elm.ownerDocument.documentElement || elm.ownerDocument.constructor.name === 'DocumentFragment'){ // is <html> or in a fragment
            context = elm.ownerDocument;
        }
    }
    if(!context){ // still no context? do David Thomas' method
        df = document.createDocumentFragment();
        df.appendChild(elm);
        list = df.childNodes;
        // df.removeChild(elm); // NodeList is live, removeChild empties it
        return list;
    }
    // selector method
    elm.setAttribute('wrapNodeList','');
    list = context.querySelectorAll('[wrapNodeList]');
    elm.removeAttribute('wrapNodeList');
    return list;
}


There is another way to do this I thought of recently

我最近想到了另一种方法来做到这一点

var _NodeList = (function () {
    var fragment = document.createDocumentFragment();
    fragment.appendChild(document.createComment('node shadows me'));
    function NodeList (node) {
        this[0] = node;
    };
    NodeList.prototype = (function (proto) {
        function F() {} // Object.create shim
        F.prototype = proto;
        return new F();
    }(fragment.childNodes));
    NodeList.prototype.item = function item(i) {
        return this[+i || 0];
    };
    return NodeList;
}());

Now

现在

var list = new _NodeList(document.body); // note **new**
list.constructor === NodeList; // all these are true
list instanceof NodeList;
list.length === 1;
list[0] === document.body;
list.item(0) === document.body;

回答by bfavaretto

If you're targeting browsers that support document.querySelectorAll, it will always return a NodeList. So:

如果您的目标是支持 的浏览器,document.querySelectorAll它将始终返回NodeList. 所以:

var nodelist = document.querySelectorAll("#mydiv");

回答by Orbiting Eden

var nodeList = document.createDocumentFragment();
nodeList.appendChild(document.getElementById("myDiv"));

回答by Lain inVerse

Yet another way to do this based on Reflect.construct: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct

另一种基于 Reflect.construct 的方法:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct

As in other cases it requires patching NodeList.prototype.item to make calls to this function work.

与其他情况一样,它需要修补 NodeList.prototype.item 才能调用此函数。

NodeList.prototype.item = function item(i) {
    return this[+i || 0];
};
let nl = Reflect.construct(Array, [], NodeList);

To create it with nodes pass array of nodes as second argument. This method passes checks:

要使用节点创建它,请传递节点数组作为第二个参数。此方法通过检查:

list instanceof NodeList; // true
list.constructor === NodeList; // true

Array, created with it, is iterable with for..of, forEachand other standard methods and you can add elements into it with simple nl[n] = node;.

用它创建的数组可以用和其他标准方法迭代for..offorEach你可以用 simple 向其中添加元素nl[n] = node;