бесконечный цикл через элемент prepend в DOM - PullRequest
3 голосов
/ 15 марта 2012

Не ищу рамки использования XXX Ответ

Этот вопрос не предназначен для поиска практического решения с помощью фреймворка. Отвечая использовать фреймворк XXX или , это так просто в фреймворке XXX , или , почему бы не использовать этот фреймворк XXX ???

У меня есть функция, предназначенная для запуска после загрузки страницы: performShim. Эта функция перебирает все элементы в DOM, которые являются тегами span, проверяет, имеют ли они className из shim, и, если это так, вызывает shim, передавая ему ссылку на соответствующий элемент.

Моя цель состояла в том, чтобы добавить другой span, содержащий iframe к элементу, который передается в shim.

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

Мне не совсем понятно, почему это так.

function shim( element ) {      
    var iframe = document.createElement('iframe');
    iframe.setAttribute( 'frameborder', '0' );
    iframe.setAttribute( 'scrolling', 'no' );
    iframe.setAttribute( 'align', 'bottom' );
    iframe.setAttribute( 'marginheight', '0' );
    iframe.setAttribute( 'marginwidth', '0' );
    iframe.setAttribute( 'src', "javascript:'';" ); 

    var span = document.createElement('span');
    span.appendChild(iframe);


    //element.parentNode.insertBefore(span,element); //causes infinite loop?

    element.parentNode.appendChild(span); //this line works OK

    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'inline';
    var width = element.offsetWidth;
    var height = element.offsetHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;

    iframe.style.width = (width-6) + 'px';
    iframe.style.height = (height-6) + 'px';

}   

function performShim() {
    var children = document.getElementsByTagName("span");   
    for( var i = 0; i < children.length; i++ ) {
        if( children[i].className == "shim" ) {
            shim(children[i]);  
        }
    }
} 

1 Ответ

8 голосов
/ 15 марта 2012

A NodeList (например, возвращаемый document.getElementsByTagName) обычно представляет собой live список - изменения, которые вы вносите в DOM, также отображаются в нем. Поэтому каждый раз, когда вы добавляете span перед текущим, вы расширяете список на один элемент и перемещаете текущий элемент на один, а следующая итерация возвращает вас обратно к узлу, который вы только что завершили.

У вас есть несколько простых способов для этого ...

  • Увеличьте счетчик при добавлении узла. (Ужасно, и если вы когда-нибудь добавите что-то вместо span, вы в конечном итоге пропустите узлы, и он победит не понятно почему.)

  • Скопировать список в массив и выполнить итерацию по массиву. Вы могли бы сделать это с чем-то вроде
    children = [].slice.call(children, 0); (чаще) или
    children = Array.apply(window, children);.

  • Используйте document.querySelectorAll, который возвращает вам NodeList, который не является живым. (И даже если бы это было вживую, в этом случае вы можете выбрать 'span.shim', и вставленные пролеты в любом случае не будут отображаться в нем.)

  • Итерация в обратном направлении (от children.length - 1 до 0).

...