18-js基础-事件执行顺序

597 阅读2分钟

参考

自己遇到过的问题:你在input里输入完内容,点击提交按钮,会先发生blur事件,后发生click事件。最后把click使用mousedown来取代click方法。

JavaScript-父子dom同时绑定两个点击事件,一个用捕获,一个用冒泡时执行顺序

1. 原生事件的发生顺序

一般来讲,当为一个a标签添加click事件以后,点击这个标签,会先执行绑定的事件、后跳转页面。一个input绑定blur事件以后,你在input里输入完内容,点击提交按钮,会先发生blur事件,后发生click事件。当然,这是一般来讲。我在一个React项目中曾经发生表单提交时,先发生click事件,blur事件没有来得及发生,造成表单内容没有检验就提交到后台,原因我至今没有找到,解决办法是在click事件上加一个50ms的延迟。

绑定多个事件,且由用户行为触发

这个情况最复杂,也是标题中的情况:父元素与子元素都绑定多个事件,且有的事件在捕获阶段、有的事件在冒泡阶段。

下面这个例子,父元素div绑定两个事件(一个冒泡阶段、一个捕获阶段),子元素也是这种情况。事件触发顺序如何。

var btn = document.querySelector('button');
var div = document.querySelector('div');

btn.addEventListener('click', function(){
    console.log('bubble','btn');
},false);
btn.addEventListener('click', function(){
    console.log('capture','btn');
},true);

div.addEventListener('click', function(){
    console.log('bubble','div');
},false);
div.addEventListener('click', function(){
    console.log('capture','div');
},true);12345678910111213141516

执行结果: 这里写图片描述 乍一看这个结果有些乱,但仔细分析可以得出结论绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件。所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事件 -> 其他元素冒泡阶段事件 。

参考

举个例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">

    </style>
</head>
<body>
    <div class="outer">
        <div class="inner">
            <button id="btn">click</button>
        </div>
    </div>

    <script>
        const inner = document.querySelector('.inner');
        const outer = document.querySelector('.outer');
        const body = document.body;
        function h(stopPropagation){
            return function(e){
                console.log(`${this.id||this.className||this.tagName}`);
                if(stopPropagation){e.stopPropagation();}
            }
        }
        body.addEventListener('click',h()); //冒泡阶段执行
        outer.addEventListener('click',h(),true); //捕获阶段执行
        inner.addEventListener('click',h(true)); //冒泡阶段执行,取消冒泡

        //解析:W3c执行顺序:其他元素的捕获事件,自身元素的顺序事件,其他元素的冒泡事件。
        //此处,
        //body的click事件为冒泡阶段,暂不执行;
        //outer的click事件为捕获阶段执行,触发。输出outer
        //inner的click事件为冒泡阶段执行,本身触发,输出inner。
        //但是因为inner在这里取消了冒泡,所以body的click冒泡事件也不能执行了。


    </script>
</body>
</html>1234567891011121314151617181920212223242526272829303132333435363738394041

结果是: outer inner

<

改动,若此处:inner.addEventListener(‘click’,h()); //不取消冒泡 输出: outer inner body