2012-03-14 12 views
3

不是在尋找一個使用框架XXX回答無限循環的DOM

這個問題是不是爲了尋求通過框架的實用解決方案。回答使用框架XXX這很容易在框架XXX爲什麼不使用這個框架XXX?不回答這個問題。

我有一個函數意味着在頁面加載後運行:performShim。此函數迭代DOM中所有span標籤中的元素,檢查它們是否具有classNameshim,如果是,則調用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]); 
     } 
    } 
} 
+0

'這個問題不是爲了找到一個實際的解決方案'然後它是在錯誤的地方。 – 2012-03-14 20:07:03

+2

@LightnessRacesinOrbit:您忽略了* [...]通過框架*,這是一個完全有效的需求。 – 2012-03-14 20:16:28

+0

對不起,這個問題是爲了更好地理解DOM和DOM相關的純JavaScript功能,而不是更好地理解框架如何讓你的生活更輕鬆。對給出的答案我很滿意。 – user17753 2012-03-14 20:24:18

回答

8

一個NodeList(如document.getElementsByTagName返回的一個)通常是現場列表 - 您對DOM變化,它顯示爲好。因此,每次在當前元素之前添加一個span,就會將該元素擴展一個元素,並將當前元素移動一個元素,然後下一個迭代將您放回剛剛完成的節點。

你有幾個簡單的解決方法爲...

  • 凹凸計數器,當你添加一個節點。 (難看,如果你最終會增加一些,而不是一個span的,你最終會跳過節點,它不會是顯而易見的,爲什麼。)

  • 複製列表到一個數組和迭代這個數組。你可以用類似
    children = [].slice.call(children, 0);(更常見)或
    children = Array.apply(window, children);這樣做。

  • 使用document.querySelectorAll,它返回一個不存在的NodeList。 (即使它是活的,在這種情況下,您可以選擇'span.shim',並且插入的跨度不會顯示在其中)。

  • 向後迭代(從children.length - 1到0)。

+2

+1。 *下一次迭代讓你回到剛剛完成的節點*這是重要的部分。追加是「很好」(在這種情況下),因爲在下一次迭代中,您將處理另一個節點,最終您將用'shim'類運行'span'節點。但是如果生成的'span's也被分配了'shim'類,它也會產生一個無限循環。 – 2012-03-14 20:08:07

+0

那麼在'performShim'中變量'children'只是對現場列表的引用?如果是這樣的話,爲什麼追加'span'工作得很好,但是prepending不會呢? – user17753 2012-03-14 20:08:42

+2

@ user1169578:查看我的評論。關於預先考慮,考慮讓節點「a,b」。你的循環變量是'i = 0'。現在你處理'a'並且預先加入節點'c'。結果是'c,a,b'。你的循環變量前進到'i = 1',這又是節點'a' ......等等。如果你追加,你的列表可能看起來像'a,b,c',一旦你正在處理'c',你就贏了不再追加任何節點,因爲'c'沒有'shim'類。 – 2012-03-14 20:09:02