ПРИМЕЧАНИЕ. Прежде чем этот вопрос будет считаться повторяющимся, в нижней части этого вопроса есть раздел, в котором объясняется, почему несколько похожих вопросов не дают ответа, который я ищу.
Мы все знаем, что преобразовать NodeList в массив легко, и есть много способов сделать это:
[].slice.call(someNodeList)
// or
Array.from(someNodeList)
// etc...
Мне нужно обратное; как преобразовать массив узлов в статический список узлов?
Почему я хочу это сделать?
Не слишком углубляясь в вещи, я создаю новый метод для запроса элементов на странице, т.е.:
Document.prototype.customQueryMethod = function (...args) {...}
Пытаясь сохранить верность тому, как работает querySelectorAll
, я хочу вернуть статическую коллекцию NodeList
вместо массива.
До сих пор я подходил к проблеме тремя разными способами:
Попытка 1:
Создание фрагмента документа
function createNodeList(arrayOfNodes) {
let fragment = document.createDocumentFragment();
arrayOfNodes.forEach((node) => {
fragment.appendChild(node);
});
return fragment.childNodes;
}
Хотя это возвращает NodeList, это не работает, потому что вызов appendChild
удаляет узел из его текущего местоположения в DOM (где он должен оставаться).
Другой вариант этого включает cloning
узлы и возврат клонов. Однако теперь вы возвращаете клонированные узлы, которые не имеют ссылок на фактические узлы в DOM.
Попытка 2:
Попытка «издеваться» над конструктором NodeList
const FakeNodeList = (() => {
let fragment = document.createDocumentFragment();
fragment.appendChild(document.createComment('create a nodelist'));
function NodeList(nodes) {
let scope = this;
nodes.forEach((node, i) => {
scope[i] = node;
});
}
NodeList.prototype = ((proto) => {
function F() {
}
F.prototype = proto;
return new F();
})(fragment.childNodes);
NodeList.prototype.item = function item(idx) {
return this[idx] || null;
};
return NodeList;
})();
И он будет использоваться следующим образом:
let nodeList = new FakeNodeList(nodes);
// The following tests/uses all work
nodeList instanceOf NodeList // true
nodeList[0] // would return an element
nodeList.item(0) // would return an element
Хотя этот конкретный подход не удаляет элементы из DOM, он вызывает другие ошибки, например, при преобразовании его в массив:
let arr = [].slice.call(nodeList);
// or
let arr = Array.from(nodeList);
Каждое из вышеперечисленных действий приводит к следующей ошибке: Uncaught TypeError: Illegal invocation
Я также пытаюсь избежать «имитации» списка узлов с помощью поддельного конструктора списка узлов, поскольку я считаю, что это, вероятно, будет иметь непредвиденные последствия в будущем.
Попытка 3:
Прикрепление временного атрибута к элементам для повторного запроса к ним
function createNodeList(arrayOfNodes) {
arrayOfNodes.forEach((node) => {
node.setAttribute('QUERYME', '');
});
let nodeList = document.querySelectorAll('[QUERYME]');
arrayOfNodes.forEach((node) => {
node.removeAttribute('QUERYME');
});
return nodeList;
}
Это работало хорошо, пока я не обнаружил, что это не работает для некоторых элементов, таких как SVG
. Он не прикрепит атрибут (хотя я проверял это только в Chrome).
Кажется, это должно быть легко сделать, почему я не могу использовать конструктор NodeList для создания NodeList и почему я не могу преобразовать массив в NodeList аналогично тому, как NodeList преобразуются в массивы?
Как правильно преобразовать массив узлов в NodeList?
Похожие вопросы, ответы на которые меня не устраивают:
Следующие вопросы аналогичны этому. К сожалению, эти вопросы/ответы не решают мою конкретную проблему по следующим причинам.
Как я могу преобразовать массив элементов в NodeList? В ответе на этот вопрос используется метод клонирования узлов. Это не сработает, потому что мне нужен доступ к исходным узлам.
Создать список узлов из одного узла в JavaScript использует подход фрагмента документа (Попытка 1). Другие ответы пытаются сделать то же самое в попытках 2 и 3.
Создание DOM NodeList использует E4X
и поэтому не применяется. И даже несмотря на то, что он использует это, он все равно удаляет элементы из DOM.
querySelectorAll
возвращал массив. Единственная реальная польза отNodeList
— это возможность работать вживую. - person 4castle   schedule 18.07.2016document.getElementsbyTagName
, возвращают NodeList, не удаляя элементы из документа. Это поведение, которое OP пытается имитировать - person Pablo Lozano   schedule 18.07.2016appendChild
, как NodeList сохраняет элементы там, где они были до запроса? Моя цель — сохранить узлы в том месте, где они были до запроса, например, как работаетquerySelectorAll
и т. д. Если это имеет смысл. Комментарий @Pablo правильный. - person KevBot   schedule 18.07.2016.childNodes
— это живой NodeList, а не статический. - person Bergi   schedule 18.07.2016appendChild
нужен в первую очередь в этой попытке. - person KevBot   schedule 18.07.2016fragment.querySelectorAll(":scope > *")
илиfragment.find("> *")
? Это должно дать вам статический список узлов, и вы можете переместить узлы в их предыдущее местоположение в DOM после их выбора. - person Bergi   schedule 18.07.2016:scope
не работает в контексте фрагмента документа. Я также пытался добавить прототипный методfind
кDocumentFragment
, который также не работал. Я использовал некоторые идеи полифилла из этот ответ - person KevBot   schedule 18.07.2016