通过DOM中的前置元素实现无限循环

不寻找使用框架XXX答案

这个问题不是为了通过框架找到实际的解决方案。回答使用框架XXX,或者这在框架XXX中很容易,或者为什么不使用这个框架XXX??不能回答问题。

我有一个在页面加载后运行的函数:performShim。此函数迭代DOM中作为span标记的所有元素,检查它们是否具有classNameshim,如果有,则调用shim向其传递匹配元素的引用。

我的目标是在span前面添加另一个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]);  
        }
    }
} 

解决方案

ANodeList(如document.getElementsByTagName返回的那个)通常是一个实时列表--您对DOM所做的更改也会显示在其中。因此,每次在当前元素之前添加span时,您就是将列表扩展了一个元素,并将当前元素移动了一个元素,而下一次迭代会将您带回到刚刚完成的节点。

您有几个简单的解决方法来解决这个问题...

  • 添加节点时撞到计数器。(丑陋的,如果您最终添加的是某项内容而不是span,您将最终跳过节点,原因将不明显。)

  • 将列表复制到数组并迭代该数组。您可以使用
    children = [].slice.call(children, 0);(更常见)或
    children = Array.apply(window, children);

  • 使用document.querySelectorAll,这将返回一个非活动的NodeList。(即使它是实时的,在这种情况下,您也可以选择'span.shim',插入的跨度无论如何都不会显示在其中。)

    /li>
  • 向后迭代(从children.length - 1到0)。

相关文章