Javascript-Объединение Нескольких Нодлистов Вместе

Я изначально просил элегантный способ моделирования Array.concat() функции по результатам getElementsByTagName функция в IE или более старых браузерах, потому что казалось, что concat не поддержал. Только, конечно, это-причина, по которой возвращаемый объект не поддерживал его, потому что это не Array. Упс!

getElementsByTagName на самом деле возвращает NodeList. Таким образом, реальный вопрос: каков хороший способ получить один список всех элементов формы в документе (ввод, выбор, textarea, button), чтобы пройти через них? Массив не требуется... один NodeList было бы идеально, тоже.

обратите внимание, что я использую IE6, поскольку это для корпоративной интрасети (скоро IE8).

ответ, который я придумал:

  • стало проще и, вероятно, лучше просто поместить код в отдельную функцию и вызвать его три раза с разными нодлистами, а не беспокоиться о хорошем способе их объединить в один.

  • в конечном итоге я переключился на использование MooTools (после нескольких часов чтения по сравнению всех различных фреймворков). Итак, теперь получить массив элементов, которые я хочу, очень просто. Я рекомендую использовать JavaScript-фреймворк, как этот, а не люди бьют свои мозги, пытаясь выяснить лучший способ сделать что-то. Конечно, я все для изучения сырого языка (именно поэтому я так долго не использовал фреймворк), но это не так всегда самый быстрый способ получить вещи происходит, что в бизнесе часто имеет такое же значение, как улучшение способности кодера с языком.

обновление: почти 2 года спустя я бы просто использовал jQuery и покончил с этим!

6 ответов


чтобы объединить нодлисты, преобразуйте их в массивы с помощью 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);

Edit: (отвечая на ваш комментарий)

если у вас есть только несколько типов элементов, это нормально, но производительность уменьшается с количеством вызовов DOM, которые вы делаете. Может быть, лучше и быстрее сделать document.getElementsByTagName('*'), цикл через список и выбрать элементы с требуемым nodeName.

еще одна вещь, чтобы иметь в виду, что the Array.prototype.slice метод, используемый выше, может не работать во всех браузерах. Просмотрите начальную строку комментария#723 в шипение.js (двигатель селектора за jQuery)

конечно, лучше всего использовать библиотеки, такие как jQuery, который обрабатывает всю головную боль. Вы можете просто сделать:

$("input, select, textarea, <other tags>")

function mergeNodeLists(a, b) {
  var slice = Array.prototype.slice;
  return slice.call(a).concat(slice.call(b));
}

console.log( mergeNodeLists( inputs, selects ) ); // => [input, select]


С ES6 оператор распространения можно сделать

let arr = [...nodeList1, ...nodeList2];

var a1=document.getElementsByTagName('div'),
a2=document.getElementsByTagName('button');
a1=[].slice.call(a1, 0,a1.length).concat([].slice.call(a2, 0,a2.length))

Я думал, что было бы больше ответов, чем это, в любом случае я дал этому выстрел, и придумал следующую функцию, хотя мне пришлось трясти головой чуть.

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));

Как отмечено в документация MDN, вы также можете использовать Array.from чтобы преобразовать NodeList в массив в браузерах, которые его поддерживают.