最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 事件传播机制

    正文概述 掘金(lio_zero)   2021-06-27   352

    JavaScript 采用异步事件驱动编程模型,与 HTML 的交互是通过事件实现的。

    当我们执行了特定的事件时,如在一个按钮上监听了 click 点击事件,当你按下按钮时,它将触发你给定的事件句柄(又称事件处理函数,其中执行一些 JS 语句)。但这个触发过程是怎样的呢?下面我们来通过一些问题来看看今天要讲的事件的传播机制。

    你可以在这?测试效果,配合下文进行阅读。

    什么是事件流?

    事件流是在网页上接收事件的顺序。当您单击嵌套在其他各种元素中的元素时,在您单击目标元素后,它会先触发目标元素上的 click 事件,在一层层往上触发事件,最终到达最顶层的 window 对象,这是浏览器默认的事件冒泡行为(IE 9+)。事件流有两种方式:

    • 从外到内(事件捕获)
    • 从内到外(事件冒泡)

    简单示例:以下问题都用该结构

    <ul id="emoji">
      <li id="smile">?</li>
      <li>?</li>
      <li>?</li>
      <li>?</li>
      <li>?</li>
      <li>?</li>
    </ul>
    
    <script>
      emoji.onclick = function (e) {
        console.log(e.target.innerHTML)
      }
    </script>
    

    尝试一下使用上面示例,你会发现,单击每个 <li> 标签,你会得到其中的每个 emoji

    能得到这样的结果是因为,它使用了事件冒泡一个最重要的原理:事件委托(event delegation),后面会介绍到。

    IE 中的事件流

    这里要介绍一下 IE 6-8 中的事件流,IE 6-8 中的事件流和标准的 DOM 事件流有(独)所(领)不(风)同(骚),IE 的事件流只支持事件冒泡,不支持事件捕获。

    IE 9 之前,它也不支持 addEventListener,也就不能使用其第三个参数来表示是冒泡还是捕获,它提供了非标准的事件侦听器 attachEvent() 方法。

    在这个模型中,事件对象使用 event.srcElement 属性,而不是 event.target,但两者的效果相同。

    emoji.attachEvent('onclick', function (e) {
      var target = e.target || e.srcElement
      alert(target.innerHTML)
    })
    

    什么是事件冒泡?

    事件冒泡是事件传播的一种,其中事件首先在最内部的目标元素上触发,然后在同一嵌套层次结构中依次在目标元素的祖先(父代)上触发,直到到达最外层的 DOM 元素。

    emoji.onclick = function () {
      alert(11)
    }
    
    smile.onclick = function () {
      alert(22)
    }
    
    // 11
    // 22
    

    什么是事件捕获?

    事件捕获也是事件传播的一种,其中事件首先被最外面的元素捕获,然后在同一嵌套层次结构中依次触发目标元素的后代(子元素),直到到达最里面的 DOM 元素。

    当一个事件发生以后,它会在不同的 DOM 节点之间传播(propagation)。DOM 事件标准描述了事件传播的 3 个阶段:

    • 捕获阶段(capture phase):事件从 Window 对象向下传递到目标节点。

    • 目标阶段(target phase):事件到达目标元素。

    • 冒泡阶段(bubbling phase):事件从元素上开始冒泡。

    在捕获阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标元素后,冒泡才开始。

    同时,这三个阶段的传播模型,会使得一个事件在多个节点上触发。

    因为浏览器默认是从事件冒泡开始,我们看不到事件捕获,所以想要测试事件捕获我们需要使用到 addEventListener 方法,addEventListener 用于添加事件句柄、注册监听器,参数三还可以指定在捕获阶段还是冒泡阶段触发事件:

    • false(默认值)—— 在冒泡阶段开始触发事件;
    • true —— 在捕获阶段开始触发事件。
    smile.addEventListener('click', function(e) {
      console.log(e.target.innerHTML)
    })
    
    emoji.addEventListener('click', function(e) {
      alert('Emoji List')
    }, true)
    
    document.addEventListener('click', function () {
      alert('document')
    })
    
    window.addEventListener('click', function () {
      alert('window')
    })
    
    // 点击 smile 时,将依次输出 'Emoji List' -> ? -> 'document' -> 'window'
    // 由于将 list 设置为捕获阶段开始,所以先触发,在触发 ?,然后在依次往上触发。
    

    事件委托

    事件委托,也称为事件代理,是指将本要添加在自身的事件,添加到别人身上。通过冒泡的原理,将事件添加到父级,触发执行效果。

    emoji.addEventListener('click', function(e) {
      console.log(e.target.innerHTML)
    })
    

    好处

    • 节省内存占用,减少事件注册
    • 新增子对象时,无需再对其进行事件绑定

    阻止事件传播

    使用 event.stopPropagation() 方法用于阻止捕获和冒泡阶段中当前事件在 DOM 中的进一步传播。

    function handler(e) { 
      e.stopPropagation()
    }
    

    取消默认事件

    使用 event.preventDefault() 方法取消浏览器对当前事件的默认行为,例如:

    • 表单元素中使用,它将阻止其提交
    • 锚元素中使用,它将阻止其导航
    • 上下文菜单中使用,它将阻止其显示或隐藏
    function handler(e) { 
      e.preventDefault()
    }
    

    您还可以在事件对象中使用 event.defaultPrevented 查看是否使用了 event.preventDefault() 方法。

    它返回一个布尔值用来表明是否在特定元素中调用了event.preventDefault()

    function handler(e) {
      e.preventDefault()
      console.log(e.defaultPrevented) // true or false
    }
    

    return false 用法涉及哪些步骤

    事件处理程序中的 return false 语句执行以下步骤:

    • 首先,它停止了浏览器的默认操作或行为。
    • 它防止事件传播 DOM
    • 停止回调执行,并在调用时立即返回。

    理解事件传播需要注意

    • 事件本身在传播,而不是绑定在事件上的方法会传播;
    • 并非所有的事件都会传播,像 focusblur 事件就不传播,mouseentermouseleave 事件也不会传播;
    • 您应该知道哪些事件有默认行为,并在需要时阻止它。
    • 如果是使用 on<event> 分配的处理程序,那么你可以使用 return false 来阻止默认行为。
    • 事件处理程序返回的值通常会被忽略。唯一的例外是从使用 on<event> 分配的处理程序中返回的 return false。在所有其他情况下,return 值都会被忽略。并且,返回 true 没有意义。
    • 如果是使用 addEventListener,你可以使用 return false,但常用的是使用 event 对象中 e.preventDefault() 方法来阻止默认行为的发生。
    • return false 做着与 event.stopPropagation()event.preventDefault() 类似的工作,但它们之间毫无关联。

    起源地下载网 » JavaScript 事件传播机制

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元