Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS 中的事件传播机制和使用场景 #25

Open
lurenacm opened this issue Jul 23, 2021 · 0 comments
Open

JS 中的事件传播机制和使用场景 #25

lurenacm opened this issue Jul 23, 2021 · 0 comments

Comments

@lurenacm
Copy link
Owner

lurenacm commented Jul 23, 2021

一、事件

  • 事件就是一件事情或行为是元素天生自带的,比如鼠标事件,键盘事件等

1. 事件绑定

  • DOM0: element.onXXX = function(){},例如 box.onclick = function(){}, box.onclick = null。DOM0 事件绑定利用的是给已经存在的私有属性赋值,事件绑定后浏览器会建立监听机制。
  • 事件监听 DOM2:element.addEventListener('xxx', function(){}, false), element.removeEventListener('xxx', fn)
  • 事件捕获:element.attachEvent('xxx', function(){}),DOM2 中的监听事件可以给同一个元素对象绑定多个事件形成事件池,事件的执行顺序是按队列的结构依次执行。addEventListener('xxx', function(){}, false)xxx 是DOM中的事件也可以自定义,function(){} 中的 this 指向 element
  • addEventListener(), 第三个参数默认值是 false。true:表示事件在捕获阶段执行false 表示事件在冒泡阶段执行
  • 上面的方法执行时浏览器会传递一个事件对象,根据绑定的事件不同,浏览器传递的事件对象也就不同
    一个小例子
oBox.onclick = function(ev){
}
oBox1.onclick = function(ev){
}

onclick
onkeydown

  • 一些比较重要的事件对象属性

target:操作的元素,preventDefault:阻止默认行为。stopPropagation:阻止冒泡事件的传播。

2. 事件默认行为

默认行为:事件本身就带有的,即使没有绑定方法,也会存在一些默认效果,这些默认效果就是默认行为。比如 <a></a> 标签的点击行为:页面跳转,HASH 定位(锚点定位)。(扫个盲:锚点定位是在根目录下给a标签的链接加上一个标识 <a href='#xx'></a> 和页面的某个节点的 ID xx 匹配。)

<a href="#box1">我跳到box1</a>
<a href="#" name="#box2">我跳到box2</a>

<div id="box1"></div>
<div id="box2"></div>

HASH 定位能够无刷新页面将数据返回。可用于 SPA 单页应用。

3. 阻止默认行为

  • 使用 preventDefault,以 <a></a> 示例
[a标签].onclick = function(event) {
    event = event || window.event   // 兼容浏览器
    event.preventDefault ? event.preventDefault() || return false
}
<!-- 或者 -->
<a href="javascript:;"></a>
<a href="javascript:void 0;"></a>
<a href="javascript:undefined;"></a>
<a href="javascript:null;"></a>

4. 事件传播机制

  • 事件的 冒泡传播机制 指:触发子元素的事件,父元素的事件也被相继触发,一般认为 body 是最外层的元素,这个传播过程就是事件冒泡。
  • 事件 捕获机制:当内部事件触发时,浏览器首先会在外层元素向内查找,找到事件触发的源头,这个过程就是捕获事件。而捕获的目的是为了规划冒泡的传播路径。

所以触发事件后,先有捕获事件->到执行目标事件->才有冒泡事件。

小思考

  • 移动浏览器单击为什么有 300ms 延迟的问题?怎么解决?
    1. 原因:在 PC 端 click 事件属于点击事件可以连续双击。在移动端的 click 代表的是单击行为,移动端是以 300ms 为零界限判断是否再有点击行为,如果在 300ms 内再次点击是属于双击的。300ms 外点击才是下一次单击。
    2. 解决:禁用缩放
    <meta name="viewport" content="user-scalable=no" />
        html {
        touch-action: manipulation;
    }
    /* 或者*/
        html {
            touch-action: manipulation; // IE11+
            -ms-touch-action: manipulation; // IE10
        }
    • 不禁用缩放
        <meta name="viewport" content="width=device-width" />

二、事件委托(事件代理)

事件委托是指:一个容器内的很多子元素都需要做某些相同事的话,那么可以利用 冒泡传播机制 直接在父容器上处理子元素要做的事,这样就不需要给每个子元素都绑定方法,根据事件对象中的事件源 ev.target 来做处理。

  • 场景:菜单折叠等。

事件委托的场景题1

  • 获取标签 ul 下的所有子标签li
<ul>
    <li>1<li/>
    <li>2<li/>
    <li>3<li/>
    <li>4<li/>
    <li>5<li/>
</ul>
let ul = document.querySelector('ul')
ul.addEventListener('click', function(e){
    console.log(e.target.tagName.toLowerCase())
    if(e.target.tagName.toLowerCase() === 'li') {
        let liList = document.querySelectorAll('li')
        // 类数组需要使用 call 指定调用对象
        let index = Array.prototype.indexOf.call(liList, e.target)
        console.log(e.target.innerHTML, index)
    }
})

(面试题)event.stopPropagation() 和 event.preventDefault() 区别

  • stopPropagation() 是用于阻止事件的进一步传播,但是不能阻止事件的默认行为,像 a 标签点击的默认跳转行为
  • preventDefault() 可以阻止默认行为。

使用场景二

  • 假设一个用户被禁封,点击页面任何按钮时,alter 出禁封的信息实现。可以使用捕获阶段排阻止用户的事件传播
//param: banner: 表示该用户被禁封
window.addEventListener('click', function(e){
    if(banner === true){
        e.stopPropagation()
    }
}, true)

(面试题)event.target 和 event.currentTarget 的区别

  • event.target 是 触发事件的元素。
  • event.currentTarget 是绑定事件监听的元素。

参考

2019 再聊移动端 300ms 延迟及 fastClick 原理解析

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant