• javascript 事件传播与事件冒泡,W3C事件模型


    说实话笔者在才工作的时候就听说了什么"事件冒泡",弄了很久才弄个大概,当时理解意思是子级dom元素和父级dom元素都绑定了相同类型的事件,这时如果子级事件触发了父级也会触发,然后这就叫做"事件冒泡"。然而,事情要是这么简单的话,相信笔者这时一定已经迎娶了白富美,当上了CEO。坏就坏在后来又听说一个"事件传播" ,尼玛不是"事件冒泡"吗,然后又听说了"W3C事件模型"。。。到了最后笔者彻底心碎了,只能乖乖的当忙农了!!!

    咱们先说说里面的术语,"事件捕获"、"事件冒泡"、"事件传播"、"事件注册"、"W3C事件模型"

    "事件注册":事件注册有好多方式,大概有下面这些

    1、直接在dom元素上加,这其实是很挫的方式,然并卵,现在仍然有好多淫在用

    <input type="button" onclick="alert('打的好')" name="button" value="痛击我啊">

    2、使用js程序在dom元素对象上加"onxxx"的形式

    <input type="button" id="btn"  name="button" value="痛击我啊">
    
    document.getElementById('btn').onclick = function(){alert('打的好');};

    3、使用诸如'addEventListener'、'attachEvent'函数

    var dom = document.getElementById('btn');
    var hander = function(){alert('打的好');};
    if(dom.addEventListener){
      dom.addEventListener('click', hander, false);//支持标准w3c浏览器专用
    }else{
     dom.attachEvent('onclick', hander);//非标准w3c浏览器专用
    }

    4、逼格更加高点的"事件委托",意思就是委托别人帮助自己响应事件,如下

    <div id="father" style="background: green;">
            我是父亲啊</br> 
            呵呵啊</br> 
            <div id="son" style="background: blue;">
                我是儿子啊
            </div> 
        </div>
    document.getElementById('father').onclick = function(event){
                event = event || window.event;
                var target = event.srcElement || event.target;
                if(target.getAttribute('id') === 'son'){ alert('你点击了儿子!');}
            }

    点击"我是儿子啊"弹出框框,点击"我是父亲啊" 什么都没有弹,当然了,你不仅可以委托父级元素,也可以委托和你无关的元素

    "事件冒泡" 和 "事件传播":

    两个一起说了,是有历史原因的,早期有两冤家,网景和微软,它俩啥都对着干,网景搞"事件传播",微软对着干搞"事件冒泡",这俩货有啥区别了,网上有人专门画了一张图

    "事件冒泡"就是那个绿色的箭头,"事件传播"就是那个红色的箭头

    "事件冒泡"就从目标元素"td"一直冒到根"window", "事件传播"就从根"window"一直传到"td"元素, 是不是编程都反着干,真是冤家

    这时候联合国"w3c"来了, 这不行啊,不能由着他们乱搞啊,不然这天下不就乱了,但是这两家伙实力比较强,又不能不考虑他们啊,于是W3C采用中和方案制定标准,规定"任何事件首先向下传播直到遇到目标元素,然后再向上冒泡返回" ,这注意好这问题统一了,并且都照顾了大家,我这秘书长位置稳保!!!

     所以,你上面看到了两个函数"attachEvent" 和 "addEventListener", 其中"attachEvent"是IE8及其之前的IE浏览器专用,只支持"事件冒泡","addEventListener" 是所有支持

    W3C标准事件模型的浏览器专用,即支持"事件冒泡" 又支持 "事件传播"。那对应的取消事件绑定就是 "detachEvent"和"removeEventListener" 两个函数了。那上面那个"event = event || window.event" 也是兼容浏览器用的了,因为IE8及其之前的IE浏览器不能直接获取event对象,需要从window对象获取。

    那这个"事件传播"与"事件冒泡" 有啥实际上的区别了,我们还是以一段代码来证明(由于IE8及之前的浏览器只支持"事件冒泡",因此我们这里用chrome浏览器测试)

    先HTML代码

    <div id="father" style="background: green;">
            我是父亲啊</br> 
            呵呵啊</br> 
            <div id="son" style="background: blue;">
                我是儿子啊
            </div> 
        </div>

    界面是

    document.getElementById('father').addEventListener('click', function(){
                alert('我是父亲!');
            }, true);//在事件传播阶段捕获
            document.getElementById('son').addEventListener('click', function(event){
                alert('我是儿子!');
            }, true);//在事件传播阶段捕获

    点击"我是儿子啊" 是不是会弹出两次,然后我们换成下面这段再看会弹出几次

    document.getElementById('father').addEventListener('click', function(){
                alert('我是父亲!');
                event.stopPropagation();
            }, true);
            document.getElementById('son').addEventListener('click', function(event){
                alert('我是儿子!');
            }, true);

    这次只弹出了一次"我是父亲" , "我是儿子" 那句没有执行,这是啥原因了?

    因为这里设定在事件传播阶段捕获事件,事件是先传播到'father'元素中的,在'father'元素中调用了'event.stopPropagation()'阻止事件进一步捕获,因此事件将不再传播到'son'元素中 (注意,好多淫把阻止事件传播或者冒泡 与 阻止默认事件 弄混淆了, 阻止默认事件的函数为 'preventDefault' 和 'returnValue = false;', 一个W3C标准浏览器专用,一个IE8及之前版本的IE专用)

    再来看在事件冒泡阶段进行捕获,会是怎样的结果,代码如下

    document.getElementById('father').addEventListener('click', function(){
                alert('我是父亲!');
            }, false);
            document.getElementById('son').addEventListener('click', function(event){
                alert('我是儿子!');
             event.stopPropagation();
            }, false);    

    这次再点击"我是儿子啊" 只弹出了"我是儿子","我是父亲" 没有弹出,这是啥原因了?

    因为上面代码设定了在事件冒泡阶段捕获,事件先进入传播阶段 传播到'fanther', 'son'  然后到达目标元素 'son', 然后按照W3C的规定 以 事件冒泡 方式返回,先是到达'son', 但是在'son'这里被阻止了,因此不再往上冒泡,只能捕获'son'中的事件了

    "事件捕获":看了上面那么多,鄙人觉得这个就不用解释了吧

    "W3C事件模型":这个,笔者貌似在上面也解释了,不用说了吧

    鄙人才疏学浅,有不足之处,欢迎补足!!!

  • 相关阅读:
    How to disable ipv6 in ubuntu
    git 暂存区问题
    linux 自动输入密码脚本避免密码确认
    【Linux学习简记 】数据流重定向<,<<,>,>>,2>,2>>
    【Gradle教程】Gradle 基础入门
    vsftpd配置匿名下载,登录上传
    Thunar左侧边栏不完全显示PLACES的解决
    【Jenkins系列教程】流水线通过SSH方式操作Git仓库
    害你加班的bug就是我写的,记一次升级Jenkins插件引发的加班
    Linux 临时终端连接无线网
  • 原文地址:https://www.cnblogs.com/painsOnline/p/5106310.html
Copyright © 2020-2023  润新知