1. 程式人生 > >[js高手之路]設計模式系列課程-委托模式實戰微博發布功能

[js高手之路]設計模式系列課程-委托模式實戰微博發布功能

i++ 發布 動態 use shee 內容 標題 cnblogs 文件

在實際開發中,經常需要為Dom元素綁定事件,如果頁面上有4個li元素,點擊對應的li,彈出對應的li內容,怎麽做呢?是不是很簡單?

大多數人的做法都是:獲取元素,綁定事件

 1     <ul>
 2         <li>跟著ghostwu學習javascript設計模式的應用1</li>
 3         <li>跟著ghostwu學習javascript設計模式的應用2</li>
 4         <li>跟著ghostwu學習javascript設計模式的應用3</li>
 5         <li>跟著ghostwu學習javascript設計模式的應用4</li>
 6
</ul> 7 <script> 8 var aLi = document.querySelectorAll( "li" ); 9 aLi.forEach(( ele, ind ) => { 10 ele.addEventListener( "click", ()=> { 11 alert( ele.innerHTML ); 12 } ); 13 }); 14 </script>

如果頁面上有1w個元素, 甚至10w個元素呢?

繼續使用上述方式,會有很大的性能問題,這個時候,有人可能要問,實際中的項目 哪有1w個,10w個元素的。一般的項目可能沒有,但是社交類的網站,如微博,其他的如大批量文件上傳等能功能,都是需要動態創建dom元素,而且數量巨大,並且創建出來的dom元素,一般都需要綁定事件和相應的特效。一般情況下,用普通的綁定事件方式是不能給動態創建的dom元素綁定到事件的,所以這裏就產生了兩個問題:

1,當頁面元素很多的時候,如果給這些元素綁定上事件?

2,當動態創建dom時,如果給動態創建的dom綁定上事件和相應的特效?

這就是本文需要討論的模式-委托模式

采用事件委托可以順利解決上面2個問題

那麽,什麽是事件委托呢?

給元素的父元素綁定事件,利用冒泡原理,當子元素觸發事件的時候,會去觸發父元素的事件,然後把相應的業務邏輯放在父元素的事件中去處理。通俗點講就是,子元素不做事件綁定,把綁定事件的操作委托給父元素,這就叫做事件委托, 委托有一個特性,他能夠在事件觸發中,識別到具體是由哪個子元素觸發的,這個就是事件對象的target屬性

 1     <ul>
 2         <li>跟著ghostwu學習javascript設計模式的應用1</li>
 3         <li>跟著ghostwu學習javascript設計模式的應用2</li>
 4         <li>跟著ghostwu學習javascript設計模式的應用3</li>
 5         <li>跟著ghostwu學習javascript設計模式的應用4</li>
 6     </ul>
 7     <script>
 8         var oUl = document.querySelector("ul");
 9         oUl.addEventListener( "click", ( ev )=>{
10             var oEvent = ev || event;
11             target = oEvent.target || oEvent.srcElement;
12             alert( target.innerHTML );
13         });
14     </script>

當我們點擊li的時候,就能通過事件對象oEvent.target識別到觸發事件的li元素, srcElement是兼容ie的寫法。

在沒有事件委托之間,我們通過javascript做一個hover的功能,一般這麽做.

 1     <ul>
 2         <li>跟著ghostwu學習設計模式</li>
 3         <li>跟著ghostwu學習設計模式</li>
 4         <li>跟著ghostwu學習設計模式</li>
 5         <li>跟著ghostwu學習設計模式</li>
 6         <li>跟著ghostwu學習設計模式</li>
 7     </ul>
 8     <script>
 9         var aLi = document.getElementsByTagName( "li" );
10         for( var i = 0, len = aLi.length; i < len; i++ ){
11             aLi[i].onmouseover = function(){
12                 this.style.backgroundColor = ‘red‘;
13             }
14             aLi[i].onmouseout = function(){
15                 this.style.backgroundColor = ‘‘;
16             }
17         }
18     </script>

如果li元素很多,就會產生性能問題,而采用委托模式,我們可以這麽做

 1     <ul>
 2         <li>跟著ghostwu學習設計模式1</li>
 3         <li>跟著ghostwu學習設計模式2</li>
 4         <li>跟著ghostwu學習設計模式3</li>
 5     </ul>
 6     <script>
 7         var aLi = document.getElementsByTagName("li");
 8         var oUl = document.getElementsByTagName( "ul" )[0];
 9         oUl.onmouseover = function( ev ){
10             var oEvent = ev || event;
11             var target = oEvent.target || oEvent.srcElement;
12             if ( target.tagName.toLowerCase() == ‘li‘ ) {
13                 target.style.backgroundColor = ‘red‘;
14             }
15         }
16         oUl.onmouseout = function( ev ){
17             var oEvent = ev || event;
18             var target = oEvent.target || oEvent.srcElement;
19             if ( target.tagName.toLowerCase() == ‘li‘ ) {
20                 target.style.backgroundColor = ‘‘;
21             }
22         }
23     </script>

通過事件委托,把元素綁定到父元素,大大提高性能

至此,我們解決了第一個問題:當頁面元素很多的時候,如果給這些元素綁定上事件

對於新創建的dom元素,普通綁定事件的方式,是不能綁定到這些dom元素的

 1      <input type="button" value="創建">
 2    <ul>
 3        <li>ghostwu1</li>
 4        <li>ghostwu2</li>
 5    </ul>
 6     <script>
 7         var oBtn = document.getElementsByTagName( "input" )[0];
 8         var oUl = document.getElementsByTagName( "ul" )[0];
 9         var aLi = document.getElementsByTagName( "li" );
10         oBtn.onclick = function(){
11             var oLi = document.createElement( "li" );
12             oLi.innerHTML = ‘ghostwu‘;
13             oUl.appendChild( oLi );
14         }
15         for( var i = 0, len = aLi.length; i < len; i++ ){
16             aLi[i].onmouseover = function(){
17                 this.style.backgroundColor = ‘red‘;
18             }
19             aLi[i].onmouseout = function(){
20                 this.style.backgroundColor = ‘‘;
21             }
22         }
23 
24     </script>

新創建的li元素,是不能綁定到onmouseover和onmouseout事件的,我們采用委托模式之後,可以這麽做

 1     <input type="button" value="創建">
 2     <ul>
 3         <li>ghostwu1</li>
 4         <li>ghostwu2</li>
 5     </ul>
 6     <script>
 7         var oBtn = document.getElementsByTagName("input")[0];
 8         var oUl = document.getElementsByTagName("ul")[0];
 9         var aLi = document.getElementsByTagName("li");
10         oBtn.onclick = function () {
11             var oLi = document.createElement("li");
12             oLi.innerHTML = ‘ghostwu‘;
13             oUl.appendChild(oLi);
14         }
15         oUl.onmouseover = function( ev ){
16             var oEvent = ev || event;
17             var target = oEvent.target || oEvent.srcElement;
18             if ( target.tagName.toLowerCase() == ‘li‘ ) {
19                 target.style.backgroundColor = ‘red‘;
20             }
21         }
22         oUl.onmouseout = function( ev ){
23             var oEvent = ev || event;
24             var target = oEvent.target || oEvent.srcElement;
25             if ( target.tagName.toLowerCase() == ‘li‘ ) {
26                 target.style.backgroundColor = ‘‘;
27             }
28         }
29     </script>

至此,我們解決了第二個問題:當動態創建dom時,如果給動態創建的dom綁定上事件和相應的特效

最後,我們結合委托模式,來實戰一個微博發布的功能,微博發布之後,給動態創建的dom元素添加手風琴折疊功能

技術分享

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link href="https://cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-md-offset-3 col-md-6">
                <form class="form-horizontal">
                    <div class="form-group">
                        <input id="title" type="text" class="form-control" placeholder="請輸入標題">
                    </div>
                    <div class="form-group">
                        <textarea name="" id="txt" cols="30" rows="5" class="form-control"></textarea>
                    </div>
                    <div class="form-group">
                        <input type="button" value="發布" class="btn btn-primary" id="btn-publish">
                    </div>
                </form>
            </div>
            <div class="col-md-offset-3 col-md-6" id="content">
            </div>
        </div>
    </div>
</body>
<script>
    var oBtnPublish = document.getElementById("btn-publish");
    var aTpl = [
        <div class="panel panel-success">,
           <div class="panel-heading">,
                <h4 class="panel-title">,
                   <a href="javascript:;">,
                    [title],
                    </a>,
                </h4>,
            </div>,
            <div class="panel-body">,
                [content],
            </div>,
        </div>
    ];
    var oContent = document.getElementById( "content" ),
        str = aTpl.join( "" ),
        title = ‘‘, content = ‘‘, panelParent = null;
    oBtnPublish.onclick = function(){
        str = aTpl.join( "" );
        title = document.getElementById( "title" ).value;
        txt = document.getElementById( "txt" ).value;
        str = str.replace( /\[title\]/, title );
        str = str.replace( /\[content\]/, txt );
        oContent.innerHTML += str;
    }
    oContent.onclick = function( ev ){
        var oEvent = ev || event;
        var target = oEvent.target || oEvent.srcElement;
        if ( target.tagName.toLowerCase() == a ) {
            panelParent = target.parentNode.parentNode.parentNode;
            if ( panelParent.children[1].style.display == "block" ||  panelParent.children[1].style.display == ‘‘ ) {
                panelParent.children[1].style.display = none;
            } else {
                panelParent.children[1].style.display = block;
            }
        }
    }
</script>
</html>

[js高手之路]設計模式系列課程-委托模式實戰微博發布功能