Listening for DOM Creation Event Using CSS3

有時候我們會需要偵測頁面上是否有新增的DOM,最簡單的做法是直接去listen DOMNodeInserted事件,但這方法雖然簡單卻會大幅度的影響效能(由其是頁面DOM元素多的時候),也因此MDN不建議這樣使用

沒辦法直接listen dom event那要怎麼搞?Daniel Buchner提出了一種hack,簡略的流程是這樣:針對listening DOM寫個CSS3的animation,讓在DOM建立的時候瀏覽器會生成animationStart事件,只要抓取到這個事件並且判別該animation為該DOM所產生,就可以知道有新的DOM已經建立了。

直接貼上Buchner的JSFiddle:

詳細解說:(為了方便說明,code跟JSFiddle裡的有點出入)
  1. 建立animation的keyframe:
    
    /* set up the keyframes */
    @keyframes nodeInserted {  
      from { clip: rect(1px, auto, auto, auto); }
      to { clip: rect(0px, auto, auto, auto); }  
    }
    
    @-moz-keyframes nodeInserted {  
      from { clip: rect(1px, auto, auto, auto); }
      to { clip: rect(0px, auto, auto, auto); }
    }
    
    @-webkit-keyframes nodeInserted {  
      from { clip: rect(1px, auto, auto, auto); }
      to { clip: rect(0px, auto, auto, auto); }
    }
    
    @-ms-keyframes nodeInserted {  
      from { clip: rect(1px, auto, auto, auto); }
      to { clip: rect(0px, auto, auto, auto); }
    }
    
    @-o-keyframes nodeInserted {  
      from { clip: rect(1px, auto, auto, auto); }
      to { clip: rect(0px, auto, auto, auto); }
    }
    animation本身只要讓使用者看不出來就好,這裡是從clip 1px變成clip 0px。
  2. 套用animation到想要監聽事件的DOM上面(注意是設定在會新增的DOM,而不是他的父元素)
    div.some-control {
        animation-duration: 0.001s;
        -o-animation-duration: 0.001s;
        -ms-animation-duration: 0.001s;
        -moz-animation-duration: 0.001s;
        -webkit-animation-duration: 0.001s;
        animation-name: nodeInserted;
        -o-animation-name: nodeInserted;
        -ms-animation-name: nodeInserted;        
        -moz-animation-name: nodeInserted;
        -webkit-animation-name: nodeInserted;
    }
    animation-duration設定時間極短也是為了讓使用者不要注意到有animation
  3. Javascript用來監聽事件的code:
    var listener = function(event){
        if (event.animationName == 'nodeInserted') 
            //新增DOM之後想做的動作寫在這
    }
            
    document.addEventListener('animationstart', listener , false);
    document.addEventListener('MSAnimationStart', listener , false);
    document.addEventListener('webkitAnimationStart', listener , false);
    animationstart, MSAnimationStart, webkitAnimationStart分別是不同瀏覽器會產生的事件名稱,事件發生之後就會呼叫listener,進入listener之後還需要判別這個animationName是不是我們設定的,以免錯抓到別的DOM產生的animationStart事件。
  4. 基本上還是個hack,不清楚當頁面的animation一多的時候效能如何。
  5. 瀏覽器必須支援CSS3 Animation,支援列表

沒有留言:

張貼留言