资讯专栏INFORMATION COLUMN

JavaScript系列 事件

周国辉 / 1101人阅读

摘要:推荐使用该方式进行事件的注册,可以对同一节点注册多个事件处理函数。当前冒泡流是被大多浏览器支持,因此大多赋为。阻断事件的冒泡流或者事件捕获流。资料推荐红宝书阮一峰事件模型

一步,一步前進の一步

事件是文档或者浏览器窗口中发生的一些交互瞬间。JS注册事件处理程序来预订事件,当事件发生的瞬间来执行相应的代码,进而实现 JS 和 HTML(即文档或者浏览器窗口) 的交互。

事件流

事件流描述的是从页面中接收事件的顺序。

用手指戳一下屏幕上的同心圆的中心,先点到的是最外围的大圆,还是最核心的小圆呢?这个就是事件流要处理的本质问题。早起的 IE 和 Netscape 对此有不同的观点,IE认为先点到的是最小的圆,然后在一层层的传递到最外面的大圆(事件冒泡),Netscape 正好相反,最先碰到的是最外围的大圆,然后在一层层的追踪到最精准的小圆(事件捕获)。

事件冒泡:事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

事件捕获:事件是从不太具体的节点开始产生接收,而最具体的节点应该是最后接收事件的。

事件流规范出来说,事件传递有三个阶段: 捕获阶段、目标阶段、冒泡阶段。

事件处理程序

浏览器的事件处理大概就是注册、监听。程序开始就对未来会发生的某些事情,做出预期,对预期做出正确的反应。事件处理程序就是被注册正确反应监听这个操作由浏览器自己完成。
浏览器提供了三种方法,为事件绑定监听函数。

html 属性方式

需要注意的是:此处的事件处理程序是需要带小括号的,大概的过程是当 div 接收到事件时,会将onclick后面的代码原封不动的传入JavaScript引擎执行,不加小括号就不会触发处理程序。

此方式会让 js 的代码和 html 代码杂糅在一起,不易代码的变更和维护,因此不推荐使用。

Dom 0级事件注册
div.onclick = function (event) {
  console.log("触发事件");
};

以元素节点对象的事件属性的方式进行注册,与第一种方式类似。
该事件只会在冒泡阶段触发。

Dom 2级事件注册

target.addEventListener(type, listener[, useCapture])
type事件名称,大小写敏感;listener处理函数;useCapture是否在捕获阶段触发。
推荐使用该方式进行事件的注册,可以对同一节点注册多个事件处理函数。当前冒泡流是被大多浏览器支持,因此useCapture大多赋为false。

document.addEventListener("click", hello, false);
document.addEventListener("click", hello2, false);
IE 事件处理程序

早期的 IE 浏览器只支持冒泡流,有自己的事件注册和移除的方法:attachEvent()detachEvent()

btn.attachEvent("onclick", function () {
    alert("ie browser");
});

需要注意的是处理函数的 this 是指向 window 的,而不像前两种事件处理函数的 this 会指向事件所在的 dom 节点对象。

跨浏览器事件处理程序

红宝书方案代码如下:

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

该方法是比较好的,但是处理函数执行时的 this 指向还是有一点点问题,attachEvent方式还是指向 window 的,如果想更加完善,请参考 js 忍者秘籍上面的方案。

在处理事件时,我们需要考虑一些性能的问题,有必要限制事件处理函数的数量,适当的时候将已有的事件处理程序移除掉或者采用事件委托机制减少注册的个数。下面我们简单谈谈如何移除事件处理程序。

var EventUtil = {
    removeHandler: function (elm, type, handler) {
        if (elm.removeEventListener) {
            elm.removeEventListener(type, handler, false);
        } else if (elm.detachEvent) {
            elm.detachEvent("on" + type, handle);
        } else {
            elm["on" + type] = handler;
        }
    }
}

事件的移除有个原则,怎么注册的就要原封不动的 copy 参数调用移除。此处需要注意的是当你的事件处理函数是匿名函数时,那将会永远也清理不掉了。

this 指向

处理函数执行时,this 指向现代的浏览器指向的是 事件所在dom 节点,老 IE 指向window。

事件对象

事件发生后,会产生一个事件对象,作为参数传给监听函数。事件有若干的实例属性和实例方法。只讲下笔者认为重要的currentTargettargetpreventDefault().stopPropagation()stopImmediatePropagation()

currentTarget事件处理函数注册在什么节点上,那么 currentTarget 就永远的指向了该节点。
target,我们回顾一下事件流的概念,事件会经历捕获阶段、目标阶段、冒泡阶段,可以感觉到事件的传递画了个对称的钩,target 表示事件当前所处的节点位置。
我们不仅可以读取事件的状态,还可以人为的改变它的内部状态。

preventDefault()阻止事件的默认行为,如 a 标签被点击时就会跳转到新的 url,我们可以使用event.preventDefault()来阻止跳转。

stopPropagation()阻断事件的冒泡流或者事件捕获流。但如果同一节点上注册了多个事件处理程序,那么该节点上的事件处理程序会继续处理,它只会阻断事件向上或向下的传播。

stopImmediatePropagation()更为狠毒,事件会停止在该事件处理程序上,同节点的其他事件处理程序也不会被触发了。

事件代理

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

  • test
  • test
  • test
  • test
  • test
  • ...

假设业务需要给 li 添加 click 监听事件,那么初学者可能会采用直接获取 li 节点的方式进行事件程序的绑定,那么有几个 li,就需要注册多少个事件处理程序。可以采用事件代理机制实现性能优化,代码如下:

var ul = document.querySelector("ul");

ul.addEventListener("click", function (event) {
  if (event.target.tagName.toLowerCase() === "li") {
    // some code
  }
});

事件代理和事件委托是同一个东西,主要是利用事件冒泡和事件的实例属性 target,目的是减少事件处理程序的数量,提高性能。

资料推荐

红宝书
阮一峰 事件模型

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97039.html

相关文章

  • Javascript系列javascript机制

    摘要:异步任务必须指定回调函数,当异步任务从任务队列回到执行栈,回调函数就会执行。事件循环主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为。事件循环事件循环是指主线程重复从消息队列中取消息执行的过程。 参考链接:这一次,彻底弄懂 JavaScript 执行机制https://zhuanlan.zhihu.com/p/...从浏览器多进程到JS单线程,JS运行机制...

    13651657101 评论0 收藏0
  • JavaScript系列事件类型

    摘要:有两种事件处理程序的方式。第一种第二种事件当调整浏览器的窗口到一个新的宽度或高度时,就会触发事件。事件在元素获得焦点时触发。这个事件冒泡某些浏览器不支持。事件在鼠标光标从元素外部首次移动到元素范围内时触发。事件这个事件跟踪鼠标滚轮。 JavaScript简单入门可以看看我丑丑的Github博客JavaScript简单入门 本文主要简单介绍以下几类事件: UI事件 焦点事件 鼠标与滚轮...

    chanthuang 评论0 收藏0
  • JavaScript系列事件详解

    摘要:响应某个事件的函数就叫事件处理程序或事件侦听器。为事件指定事件处理程序的方法主要有种。事件处理程序事件直接加在元素上。事件委托利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果,解决事件处理程序过多问题。事件委托优点提高性能。 JavaScript简单入门可以看看我丑丑的Github博客JavaScript简单入门 事件 JavaScript与HTML之间的交互是通过事件实现的...

    pakolagij 评论0 收藏0
  • JavaScript系列】动态绑定事件方法:(1)jquery的on方法;(2)html元素绑定

    摘要:提示如需移除事件处理程序,请使用方法。说明和绑定的点击事件被的事件覆盖。分析不同的绑定方式执行顺序属性元素事件事件。元素绑定事件删除按钮。属性绑定事件动态绑定事件方法的方法的属性绑定。 一、动态监听加载对象 当使用js或jQuery动态创建元素(例如append,appendChildren),再用on(事件, function(){...})或addEventListener监听事件...

    young.li 评论0 收藏0
  • JavaScript系列之鼠标滚轮事件

    摘要:鼠标滚轮事件当在被绑定的对象上如某个或者发生鼠标滚轮滚动时触发。 鼠标滚轮事件 当在被绑定的对象上(如:某个div或者doucument)发生鼠标滚轮滚动时触发。 在不同的浏览器中有不同的表现形式: 一、ie/chrome下的事件 : onmousewheel 事件绑定方式:on 或者 addEventListener[attachEvent] 获取滚轮事件具体信息:ev...

    vspiders 评论0 收藏0
  • 「前端面试题系列7」Javascript 中的事件机制(从原生到框架)

    摘要:要想注册过的事件能够被解除,必须将回调函数保存起来,否则无法解除。当用阻止浏览器的默认行为时,会做下面这件事停止回调函数执行并立即返回。 showImg(https://segmentfault.com/img/bVboOcb?w=750&h=422); 前言 这是前端面试题系列的第 7 篇,你可能错过了前面的篇章,可以在这里找到: 理解函数的柯里化 ES6 中箭头函数的用法 thi...

    Tony 评论0 收藏0

发表评论

0条评论

周国辉

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<