• [js高手之路]设计模式系列课程-委托模式实战微博发布功能


    在实际开发中,经常需要为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>
  • 相关阅读:
    配置Log4j(非常具体)
    RapeLay(电车之狼R)的结局介绍 (隐藏结局攻略)
    普林斯顿公开课 算法1-11:并查集的应用
    检查Oracle 中死事务的语句
    app被Rejected 的各种原因翻译
    经典语录和思考总结
    Java实现夺冠概率模拟
    Java实现夺冠概率模拟
    Java实现打印回型嵌套
    Java实现打印回型嵌套
  • 原文地址:https://www.cnblogs.com/ghostwu/p/7471471.html
Copyright © 2020-2023  润新知