2009-05-27 2 views
27

Есть ли способ присоединиться к 2 NodeLists, возвращенным двумя вызовами document.getElementsByTagName?JavaScript NodeList

Скажем, у меня есть следующий код

var inputs = documentElement.getElementsByTagName('input'); 
var selects = document.getElementsByTagName('select'); 

Я хочу Переберите результатов. Возможно ли это в одном цикле?

Спасибо заранее!

+0

Цитирование их обоих одновременно или последовательно? –

ответ

46

Похоже, вы можете использовать один и тот же Array.prototype.slice.call, что делает арг массив как объект становится массивом. (See here)

var inputs = document.getElementsByTagName('input'); 
var selects = document.getElementsByTagName('select'); 

inputs = Array.prototype.slice.call(inputs); 
selects = Array.prototype.slice.call(selects); 

var res = inputs.concat(selects); 

alert(res.length); 
+1

Я как раз собирался сказать, что :) +1 Прототип и другие библиотеки используют срез для преобразования списков узлов в массивы. –

+10

Незначительная вещь, о которой нужно помнить, заключается в том, что это не будет работать в браузере Internet Explorer или BlackBerry. jQuery 1.4 имеет интересный тест, который используется для возврата к циклу для объединения списков узлов. Я выписал его здесь: http://pastebin.com/TkTwMG17 –

4

Насколько я знаю, NodeList типа неизменна (см this article, например), что означает, что вы должны будете генерировать свой собственный объект.

Простым методом было бы создать массив и скопировать все элементы в этот массив.

var inputs = documentElement.getElementsByTagName('input'); 
var selects = document.getElementsByTagName('select'); 
var all = new Array(inputs.length + selects.length); 

var index = 0; 
for (i = 0; i < inputs.length; i++) 
    all[index++] = inputs[i]; 
for (i = 0; i < selects.length; i++) 
    all[index++] = selects[i]; 

Переменная all затем содержит объединение двух наборов узлов.

+0

В любом случае потребуется 2 петли. Для моей конкретной задачи мне нужно пропустить результаты только один раз, поэтому создание объекта не стоит. Я не могу присоединиться к результатам, и это то, что я хотел знать, спасибо! –

+0

Да, использование двух петель является самым ясным решением, на мой взгляд, в любом случае. (Я считал вариант с одним циклом, но на самом деле это не помогает.) Рад, что у вас есть решение. – Noldorin

+1

Ну. А как насчет Array.prototype.slice.call (thatNodeListOfYours, 0); ? – Witiko

0

Во-первых, я думал, что это возможно Concat массивы, используя Array.prototype, как это:

Array.prototype.concat.call(selects, inputs); 

Но это не работает, так что я сделал массивы из коллекций узлов и CONCAT Это. Похоже, что:

(function() { 

    var inputs = document.getElementsByTagName('input'), 
     selects = document.getElementsByTagName('select'), 
     result, 
     i, 
     node; 

    function convert (collection) { 
     var a = []; 
     for (var i = 0, length = collection.length; i < length; i++) { 
      a.push(collection[i]); 
     } 
     return a; 
    } 

    // concatenation && convertation 
    result = Array.prototype.concat(convert(inputs), convert(selects)); 
    // traversing 
    i = result.length; 
    while(node = result[--i]) { 
     alert(node.getAttribute('name')); 
    } 

})(); 
+0

Я считаю, что первый трюк работает в любом (крупном) браузере, кроме IE. –

+0

И первый трюк не будет работать в браузерах на основе WebKit (сафари, хром) –

20

Вы не можете присоединиться к ним, но вы можете перебрать их последовательно в один цикл, как это:

for (var i = 0; i < inputs.length + selects.length; i++) { 
    var element = (i < inputs.length) ? inputs[i] : selects[i-inputs.length]; 
} 

Кроме того, с помощью JQuery, вы можете выбрать их в один идти:

$('input, select') 
+0

+1 для обеспечения обоих опций и элегантного для цикла – annakata

+0

+1 для указания опции jQuery. –

+0

Ницца! thnaks :) –

12
document.querySelectorAll("input, select"); 
+2

требует FF 3.1+, Safari 3.1+ или IE8 + – Dementic

1

я бросил это вместе. Там может быть немного накладных расходов от выполнения , если и .length для каждого цикла, но я думаю, что его незначительный, если количество элементов не будет экстремальным.

inputs = div.getElementsByTagName('input'); 
selects = div.getElementsByTagName('select'); 
for (i=0; i<inputs.length+selects.length; i++) { 
    element = (i<inputs.length ? inputs[i] : selects[i-inputs.length]); 

    // do whatever with element 
} 
+0

Nevermind, то же, что и несколько сообщений выше ... не видел. –

1

Мой короткий код букмарклеты:

var e, t = d.getElementsByTagName('textarea'), u = d.getElementsByTagName('input'), i = t.length; 
    while(e = (i > 0) ? t[--i] : u[-i--]){ if(e.offsetHeight > 0)... } 
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]

0

В настоящее время я бы определенно использовать следующее:

Chrome, Firefox 3.5 +, IE8 +

var elements = document.querySelectorAll('a'); 

for (var i = 0, element; (element = elements[i]); i++) { 
    console.log(element); 
} 

IE11 +, Firefox 24+, 30+ Хром (с экспериментами включено)

"= элемент элементов [I]"
let elements = document.querySelectorAll('a'); 

for (let i = 0, element; (element = elements[i]); i++) { 
    console.log(element); 
} 

предпочтительнее, чем "elements.length", так как:

«Списки узлов часто реализуются как итераторы узлов с фильтром. Это означает, что получение свойства, такого как длина, равно O (n), и повторение по списку путем повторной проверки длины будет O (n^2) «.

В отличие от доступа к массиву, насколько я помню O (1).

Подробнее:

0

Array.prototype.slice.call() терпит неудачу в IE 7, используйте:

Object.prototype.getMyElements = function(tags){ 
    tags = tags.split(','); 
    var i, j, col=[], ci=0; 
    for(i=0; i<tags.length; i++) { 
     var objs = this.getElementsByTagName(tags[i]); 
     for(j=0; j<objs.length; j++) col[ci++] = objs[j]; 
    } 
    return col; 
} 
var objs = document.getMyElements('INPUT,TEXTAREA'); 
var objs = document.getElementById('myform').getMyElements('INPUT,TEXTAREA'); 
0

попробовать мой путь:

var allES = []; 
var inputs = document.getElementsByTagName("input"); 
     for (i = 0; i < inputs.length; i++) { 
       allES.push(inputs[i]); 
      } 
    // gather SELECT elements 
     var selects = document.getElementsByTagName("select"); 
      for (i=0; i < selects.length; i++){ 
       allES.push(selects[i]); 
       } 
Смежные вопросы