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

    正文概述 掘金(大海我来了)   2020-12-22   623

    事件流

    在早期 IENetscape 团队在开发第四代浏览器的时候,遇到一个问题:当点击一个按钮的时候,是应该先处理父级的事件呢?还是应该先处理按钮的事件呢?IENetscape 给出了 2 种完全相反的答案,IE 提出事件冒泡的概念,而 Netscape 则支持事件捕获。

    事件冒泡

    事件冒泡认为事件应该由最具体的元素开始触发,然后层层往父级传播:

    「面试常问」浏览器之事件机制

    事件捕获

    而事件捕获则相反,认为最外层的元素应该最先收到事件,然后层层往下级传递:

    「面试常问」浏览器之事件机制

    DOM 事件流

    为了在浏览器中兼容这 2 种事件流,在 DOM2 Events 规范中将事件流分为 3 个阶段:事件捕获阶段、到底目标阶段、事件冒泡阶段。

    「面试常问」浏览器之事件机制

    可以通过指定 addEventListener 的第三个参数为 true 来设置事件是在捕获阶段调用事件处理程序,默认是 false 指在冒泡阶段调用事件处理程序。

    事件处理程序

    HTML 事件处理程序

    就是将事件处理程序直接绑定到 HTML 的属性中:

    // 方式一
    <div onclick="console.log('hello world')"></div>
    
    方式二
    <div onclick="print(event)"></div>
    <script>
        function print(e) { }
    </script>
    

    HTML 事件处理程序修改事件相对麻烦,可能需要同时修改 HTMLJS,所以大家都不爱使用这种方式绑定事件。

    DOM0 事件处理程序

    将一个函数赋值给 DOM 元素的一个事件处理程序属性,比如 onclick

    let btn = document.getElementById('div')
    
    // 添加事件
    btn.onclick = function() { }
    
    // 移除事件
    btn.onclick = null
    

    DOM2 事件处理程序

    通过 addEventListener 可以添加 DOM2 级别的事件处理程序,它接收 3 个参数:事件名、事件处理程序和 useCapture (它是一个可选参数,是个布尔值,默认为 false 表示在冒泡阶段调用事件处理程序)

    let btn = document.getElementById('div')
    btn.addEventListener('click', () => {
        
    }, false)
    

    DOM0 事件处理程序的区别:

    • addEventListener 可以改变事件流,即可以在捕获阶段触发事件,而 DOM0 是不行的;
    • addEventListener 可以为同一个元素多次添加同一类型的事件处理程序,先添加的事件处理程序会先触发,而 DOM0 如果给同一个元素绑定多个相同类型的事件处理程序的话,则后面添加的会覆盖前面定义的;

    它有几个注意事项:

    • 如果不需要在捕获阶段进行拦截操作,则 useCapture 即第三个参可以不传;
    • 通过 addEventListener 添加的事件处理程序只能通过 removeEventListener 移除,而且绑定的事件处理程序必须是同一个。
    let btn = document.getElementById('div')
    let handler = function() { }
    btn.addEventListener("click", handler)
    btn.removeEventListener("click", handler)
    

    IE 事件处理函数

    由于 addEventListener 无法兼容 IE8 及更早版本,所以此时就可以使用 attachEvent 添加事件处理程序和用 detachEvent 移除事件处理程序。

    let btn = document.getElementById('div')
    btn.attachEvent("onclick", function() { })
    

    它有这么几个注意事项:

    • 注册的事件名和 DOM0 一样,需要带上 on,比如 onclick
    • 在通过 attachEvent 添加的事件处理程序内部 this 会指向 window,而 DOM0DOM2this 会指向元素本身;
    • addEventListener 一样, attachEvent 也可以针对同一元素多次添加同一个事件类型的处理程序,但是触发顺序是后定义的先触发;
    • 通过 detachEvent 移除事件处理程序的时候,处理函数必须是和注册的同一个,这点和 addEventListener 保持一致;

    attachEventdetachEventIE 专属的 API,所以如果有兼容性要求,我们可以写出跨浏览器的事件处理程序:

    var EventUtil = {
        addHandler: function(element, type, handler) {
            if (element.addEventListener) {
                element.addEventListener(type, handler, false)
            } else if (element.attachEvent) {
                element.attachEvent("on" + type, handler)
            } else {
                element["on" + type] = handler;
            } 
        },
        removeHandler: function(element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false)
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler)
            } else {
                element["on" + type] = null
            }
        }
    }
    

    事件对象

    通过不同的事件处理程序添加的事件,event 对象的属性略有不同,我们不需要记住他们的差异,只需要在平时写代码的时候养成一个写兼容代码的习惯即可,如下是一个兼容各种 event 对象的事件处理程序:

    let handler = function(event) {
        // 事件对象
        let event = event || window.event
        
        // 目标元素
        let target = event.target || event.srcElement
        
        // 阻止默认事件触发
        if (event.preventDefault) {
            event.preventDefault()
        } else {
            event.returnValue = false
        }
        
        // 阻止事件冒泡
        if (event.stopPropagation) {
            event.stopPropagation()
        } else {
            event.cancelBubble = true
        }
    }
    

    事件类型

    DOM3 Events 定义了如下事件类型:

    • 用户界面事件(UIEvent):涉及与 BOM 交互的通用浏览器事件,比如 onloadresizescrollinputselect 等;
    • 焦点事件(FocusEvent):在元素获得和失去焦点时触发,比如 focusblur
    • 鼠标事件(MouseEvent):使用鼠标在页面上执行某些操作时触发,比如 clickmousedownmouseover 等;
    • 滚轮事件(WheelEvent):使用鼠标滚轮(或类似设备)时触发,比如 mousewheel
    • 输入事件(InputEvent):向文档中输入文本时触发,比如 textInput
    • 键盘事件(KeyboardEvent):使用键盘在页面上执行某些操作时触发,比如 keydownkeypress
    • 合成事件(CompositionEvent):在使用某种 IME(Input Method Editor,输入法编辑器)输入字符时触发,比如 compositionstart

    事件委托

    事件委托是指将多个元素上绑定的事件通过利用事件冒泡的原理从而转移到他们共同的父级上去绑定,从而在一定程度上起到优化的作用,有的人也喜欢叫它事件代理。比如在 Vue 中经常会将事件绑定到每个列表项中:

    <ul>
        <li v-for="item in list" :key="item" @click="handleClick(item)">{{item}}</li>
    </ul>
    

    其实更好的做法是利用事件委托,将事件绑定到 ul 上:

    <ul @click="handleClick">
        <li v-for="item in list" :key="item" :data-item="item">{{item}}</li>
    </ul>
    
    handleClick(event) {
        let target = event.target
        if (target === 'li') {
            let data = target.dataset.item
        }
    }
    

    起源地下载网 » 「面试常问」浏览器之事件机制

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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