Javascript - Совместное объединение нескольких узлов
Я изначально просил элегантный способ симулировать функциональность Array.concat()
по результатам функции getElementsByTagName
в IE или более старых браузерах, потому что казалось, что concat
не поддерживается. Только, конечно, это - причина, по которой возвращенный объект не поддерживал его, потому что он не является Array
. К сожалению,
getElementsByTagName
действительно возвращает a NodeList
. Таким образом, возникает реальный вопрос: какой хороший способ получить единый список всех элементов формы в документе (ввод, выбор, текстовое поле, кнопка) для их циклирования? Массив не требуется... один и тот же NodeList
тоже был бы идеальным.
Обратите внимание, что я использую IE6, поскольку это относится к корпоративной интрасети (в скором времени IE8).
Ответ, который я придумал, был:
-
Это стало проще и, вероятно, лучше всего просто поместить код в отдельную функцию и трижды вызвать его с помощью разных нодлистов, а не беспокоиться о хорошем способе вставить их вместе в один.
-
В конечном итоге я переключился на использование MooTools (после нескольких часов чтения при сравнении всех разных фреймворков). Итак, теперь получить массив элементов, которые я хочу, очень просто. Я рекомендую использовать фреймворк javascript, подобный этому, вместо того, чтобы люди избивали свои мозги, пытаясь найти лучший способ сделать что-то. Конечно, я все на самом деле изучаю необработанный язык (вот почему я так долго держал фреймворк), но это не всегда самый быстрый способ добиться успеха, что в бизнесе часто имеет значение как улучшение способности кодера с помощью языка.
Обновление: почти через 2 года я просто использовал jQuery и покончу с этим!
Ответы
Ответ 1
Чтобы объединить нодлисты, преобразуйте их в массивы с помощью Array.prototype.slice.call
, а затем выполните их обычным образом.
var a = Array.prototype.slice.call(document.getElementsByTagName("p")),
b = Array.prototype.slice.call(document.getElementsByTagName("div"))
var c = a.concat(b);
Изменить: (ответ на ваш комментарий)
Если у вас есть только несколько типов элементов, это нормально, но производительность уменьшается с количеством сделанных вами вызовов DOM. Лучше и быстрее выполнить цикл document.getElementsByTagName('*')
, через список и выбрать элементы с требуемым nodeName
.
Еще одна вещь, о которой следует помнить, заключается в том, что использованный выше метод Array.prototype.slice
может не работать во всех браузерах. Проверьте стартовую строку комментария # 723 в sizzle.js (движок селектора за jQuery)
Конечно, лучше использовать библиотеку jQuery, которая обрабатывает всю головную боль. Вы можете просто сделать:
$("input, select, textarea, <other tags>")
Ответ 2
function mergeNodeLists(a, b) {
var slice = Array.prototype.slice;
return slice.call(a).concat(slice.call(b));
}
console.log( mergeNodeLists( inputs, selects ) ); // => [input, select]
Ответ 3
var a1=document.getElementsByTagName('div'),
a2=document.getElementsByTagName('button');
a1=[].slice.call(a1, 0,a1.length).concat([].slice.call(a2, 0,a2.length))
Ответ 4
С помощью оператора распространения ES6 вы можете сделать
let arr = [...nodeList1, ...nodeList2];
Ответ 5
Я бы подумал, что было бы больше ответов, чем это, так или иначе я дал это выстрел и придумал следующую функцию, хотя мне пришлось немного ударить головой.
function group_elements(element, tags) {
var elements = element.getElementsByTagName('*');
var results = [];
for ( var i = 0; i < elements.length; ++i ) {
if ( tags.indexOf(elements[i].nodeName.toLowerCase()) > -1 ) {
results.push(elements[i]);
}
}
return results;
}
var form = document.getElementById('form');
var tags = ['input', 'select'];
console.log(group_elements(form, tags));
Ответ 6
Как отмечено в Документация MDN, вы также можете использовать Array.from
, чтобы преобразовать NodeList в массив в браузерах, которые его поддерживают.