ПРИМЕЧАНИЕ. Прежде чем этот вопрос станет дублированным, в нижней части этого вопроса есть раздел, в котором рассматривается, почему несколько подобных вопросов не дают ответа, который я ищу.
Мы все знаем, что легко преобразовать NodeList в массив и есть много способов сделать это:
[].slice.call(someNodeList)
// or
Array.from(someNodeList)
// etc...
То, чем я являюсь, - это обратное; Как преобразовать массив узлов в статический NodeList?
Почему я хочу это сделать?
Не углубляясь в вещи, я создаю новый метод для запроса элементов на странице i.e:
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
удаляет node из его текущего местоположения в 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
Я также стараюсь избегать "подражания" nodeList с помощью поддельного конструктора нодлистов, поскольку я считаю, что, вероятно, будущие непреднамеренные последствия.
Попытка 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 так же, как NodeLists, которые будут переданы в массивы
Как преобразовать массив узлов в NodeList, правильный путь?
Аналогичные вопросы, которые не отвечают на меня:
Следующие вопросы похожи на следующие. К сожалению, эти вопросы/ответы не решают мою конкретную проблему по следующим причинам.
Как преобразовать массив элементов в NodeList? Ответ в этом вопросе использует метод, который клонирует узлы. Это не сработает, потому что мне нужно иметь доступ к исходным узлам.
Создайте node список из одного node в JavaScript, используя подход фрагмента документа (попытка 1). Другие ответы аналогичны попыткам при попытках 2 и 3.
Создание DOM NodeList использует E4X
и поэтому не применяется. И хотя он использует это, он по-прежнему удаляет элементы из DOM.