• JavaScript基础概念之----事件冒泡/捕获/委托


    事件流

    如果单击了页面中的某个按钮,同时也单击了按钮的容器元素,甚至单击了整个页面。

    IE提出的是冒泡流,网景提出的是捕获流。

    <div id="content">content
            <div id="btn">button</div>
        </div>
    
        <script type="text/javascript">
            var content = document.getElementById("content");
            var btn = document.getElementById('btn');
            btn.onclick = function(){
                alert("btn");
            };
            content.onclick = function(){
                alert("content");
            };
            document.onclick = function(){
                alert("document");
            }
        </script>
    
    //点击容器 #btn ,则弹出的顺序是:btn > content > document
    //点击容器 #content,则弹出的顺序是:content > document
    //点击容器 document,则弹出的是 document

    JS事件流原理图 :

    1、一个完整的事件流是从 window 开始,最后回到 window 的一个过程

    2、事件流被分为三个阶段:(1-5)捕获过程、(5-6)目标过程、(6-10)冒泡过程

    <div id="wrapDiv">wrapDiv
            <p id="innerP">innerP
                <span id="textSpan">textSpan</span>
            </p>
        </div>
        <script>
        var wrapDiv = document.getElementById("wrapDiv");
        var innerP = document.getElementById("innerP");
        var textSpan = document.getElementById("textSpan");
    
        // 捕获阶段绑定事件
        window.addEventListener("click", function(e){
            console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.addEventListener("click", function(e){
            console.log("document 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.documentElement.addEventListener("click", function(e){
            console.log("documentElement 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.body.addEventListener("click", function(e){
            console.log("body 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        wrapDiv.addEventListener("click", function(e){
            console.log("wrapDiv 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        innerP.addEventListener("click", function(e){
            console.log("innerP 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        textSpan.addEventListener("click", function(e){
            console.log("textSpan 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        // 冒泡阶段绑定的事件
        window.addEventListener("click", function(e){
            console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.addEventListener("click", function(e){
            console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.documentElement.addEventListener("click", function(e){
            console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.body.addEventListener("click", function(e){
            console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        wrapDiv.addEventListener("click", function(e){
            console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        innerP.addEventListener("click", function(e){
            console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        textSpan.addEventListener("click", function(e){
            console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    </script>

    如果点击textSpan元素,控制台打印如下图:

    如上图所示,事件传播的过程是先捕获,再冒泡。

     那么,如果不使用addEventListener方法绑定的事件(如onclick),会发生在哪个阶段?

    <div id="wrapDiv">wrapDiv
            <p id="innerP">innerP
                <span id="textSpan">textSpan</span>
            </p>
        </div>
        <script>
        var wrapDiv = document.getElementById("wrapDiv");
        var innerP = document.getElementById("innerP");
        var textSpan = document.getElementById("textSpan");
    
    // 测试直接绑定的事件到底发生在哪个阶段
        wrapDiv.onclick = function(){
            console.log("wrapDiv onclick 测试直接绑定的事件到底发生在哪个阶段")
        };
    
        // 捕获阶段绑定事件
        window.addEventListener("click", function(e){
            console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.addEventListener("click", function(e){
            console.log("document 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.documentElement.addEventListener("click", function(e){
            console.log("documentElement 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        document.body.addEventListener("click", function(e){
            console.log("body 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        wrapDiv.addEventListener("click", function(e){
            console.log("wrapDiv 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        innerP.addEventListener("click", function(e){
            console.log("innerP 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        textSpan.addEventListener("click", function(e){
            console.log("textSpan 捕获", e.target.nodeName, e.currentTarget.nodeName);
        }, true);
    
        // 冒泡阶段绑定的事件
        window.addEventListener("click", function(e){
            console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.addEventListener("click", function(e){
            console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.documentElement.addEventListener("click", function(e){
            console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        document.body.addEventListener("click", function(e){
            console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        wrapDiv.addEventListener("click", function(e){
            console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        innerP.addEventListener("click", function(e){
            console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    
        textSpan.addEventListener("click", function(e){
            console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName);
        }, false);
    </script>

    点击textSpan元素,如下图控制台输出:

    1、所有在目标元素上绑定的事件,都会发生在目标阶段

    2、在绑定捕获代码之前写了绑定的冒泡阶段的代码,所以在目标元素上就不会遵守先捕获后冒泡这一规则,而是先绑定的事件先发生。

    3、由于wrapDiv不是目标元素,所以它上面绑定的事件会遵守先捕获后冒泡的规则。所以用onclick直接绑定的事件发生在了冒泡阶段。

     事件委托

     对“事件处理程序过多”问题的解决方案就是事件委托

     事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

     例如,click事件会一直冒泡到document层次。我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。

    //点击li元素,输出li当中的颜色
    <ul id="box">
        <li>red</li>
        <li>yellow</li>
        <li>blue</li>
        <li>green</li>
        <li>black</li>
        <li>white</li>
    </ul>
    
    //一般会这样写
    <script>
        var colorBox = document.getElementById('box')
        var colors = colorBox.getElementsByTagName('li')
        for(var i=0;i<colors.length;i++){
            colors[i].addEventListener('click',function(e){
                var li = e.target;
                console.log(li.innerHTML)
            },false)
        }
    </script>
    
    
    //使用事件委托去写
    <script>
        var colorBox = document.getElementById('box')
        colorBox.addEventListener('click',function(e){
            var li = e.target;
            if(li.nodeName.toLowerCase() === 'li'){
                console.log(li.innerHTML)
            }
        },false)
    </script>    

    事件委托还有一个好处就是添加进来的元素也能绑定事件

    //点击li元素,输出li当中的颜色
    <ul id="box">
        <li>red</li>
        <li>yellow</li>
        <li>blue</li>
        <li>green</li>
        <li>black</li>
        <li>white</li>
    </ul>
    <button onclick="add()">add</button>
    
    <script>
        var colorBox = document.getElementById('box')
        colorBox.addEventListener('click',function(e){
            var li = e.target || e.srcElement; //兼容处理
            if(li.nodeName.toLowerCase() === 'li'){
                console.log(li.innerHTML)
            }
        },false)
    
        function add(){
            var liNode = document.createElement('li')
            var textNode = document.createTextNode('this is add text.')
            liNode.appendChild(textNode);
            document.getElementById('box').appendChild(liNode)
        }
    </script>    
  • 相关阅读:
    Ubuntu: ImportError: No module named xgboost
    Sample a balance dataset from imbalance dataset and save it(从不平衡数据中抽取平衡数据,并保存)
    Python 对不均衡数据进行Over sample(重抽样)
    汪培庄先生的个人主页
    因素空间, 人工智能的新数学理论
    百度在线笔试编程测试题(Python):整数分解成素数的积
    Android.mk 文件语法详解 转:http://blog.sina.com.cn/s/blog_602f8770010148ce.html
    Git入门指南十一:Git branch 分支与合并分支
    List of devices attached ???????????? no permissions
    Git常用命令
  • 原文地址:https://www.cnblogs.com/adhehe/p/9794168.html
Copyright © 2020-2023  润新知