欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

拨开JS事件的迷雾(一)

程序员文章站 2022-03-31 15:25:16
...

由来

当我还很菜的时候(好像就是现在~),参加过一次面试,面试官问我,给一个元素绑定事件有几种方法,虽然我JS不熟,但觉得,没吃过猪肉还没见过猪跑吗?张口就来。

行内onclick啊,bind啊,还有那个什么Event啊...

我努力在脑海中搜索见过的“猪”,他一边听一边微微点头,好像是懂了,可我自己都不确定自己说的是什么(捂脸),他没有笑出声来就算很nice了。

那次过后,我决定把没弄清楚的给好好学习下,就是这篇文的由来,算个总结,也给仍一团糊涂的朋友一点帮助。

既然是拨开“迷雾”,就不再主动制造障碍,像历史、深层次原理、某种事件类型的细节等就不再罗列,以免增加理解和记忆负担,内容较基础,高手可绕道~

事件

事件,即发生了某种行为,日常浏览网页的时候,不论是用户操作,还是开发者主动控制,都会有很多事件发生,比如:加载、点击、滚动、触摸等。所以它牵扯到几个方面因素:

在哪里发生——绑定 在何时发生——监听 发生了什么——类型 发生的过程——流程

绑定

俗话说,在哪里跌倒,就从哪里爬起来,先聊绑定。

直接上码:

<button onclick="alert(你点到我了!)"></button>
复制代码

这行代码给button绑定了一个click事件,弹出“你点到我了!”,这是最直接的方式,也是我们最初接触的方式,但显然这种结构和行为混在一起的方式是不太好的,来一点优化。

继续上码:

<button onclick="tips()"></button>
<script type="text/javascript">
    function tips(){
        alert("你点到我了!");
    }
</script>
复制代码

有了什么变化?我们把所要执行的事件内容提了出来,单独封装,这样以来,当执行内容较多时,不会让HTML显得很杂乱,而且可复用,易维护,还能怎样优化?

以上两种方式,都需要HTML的参与,即结构和行为相耦合,下面介绍不动HTML的DOM事件处理程序。

一、DOM0级事件

接着上码:

//添加

<button id=“btn”></button>
<script type="text/javascript">
    var btn=document.getElementById("btn");
    btn.onclick=function(){
        alert("你点到我了!");
    }
</script>

//删除

btn.onclick=null;
复制代码

这里是将一个函数赋值给一个事件处理程序的属性,这种方法,是DOM0级事件处理程序,出现的时间较早。

它的优点是:简单、跨浏览器,当使用更高级的方式而浏览器不支持的时候,可以回退到这种方式。

二、DOM2级事件

你没看错,不是没有DOM1级,而是DOM1级没有定义事件处理相关的东西,所以这里直接跳到2级。

So,我们来看看DOM2级的标准之下,上面的代码怎么写:

<button id=“btn”></button>
<script type="text/javascript">
    var btn=document.getElementById("btn");
    btn.addEventListener("click",function(){
        alert("你点到我了!");
    },false);
</script>
复制代码

发现了什么?它们之间只有一处不同,即事件处理程序的绑定方法——addEventListener。其标准用法如下:

addEventListener("事件名",事件处理程序,布尔值)
复制代码

前面两个很直观,但第三个布尔值是什么意思?其实它决定了事件处理程序什么时候调用,true是捕获阶段,false是冒泡阶段。多数情况下都会在冒泡阶段调用,这样能最大限度兼容浏览器,至于捕获和冒泡是什么以及有什么用处,后续单独聊。

使用DOM2级方法的主要好处,是可以添加多个事件处理程序。比如:

btn.addEventListener("click",function(){
        alert(this.id);
},false);

btn.addEventListener("click",function(){
    alert("你点到我了!");
},false);
复制代码

它们会依次按顺序执行。

既然有添加,当然要有移除,移除事件的方法就是removeEventListener()。和添加时传入的参数相同,这意味着,这种方法添加的匿名函数将无法移除。

兼容?

我们聊很多技术的时候都会做这样的区分:现代浏览器、老版浏览器。这是事物发展的必然规律,事件也不例外,那么除了上面提到的还有什么不同?——IE。

大家知道,IE通常都是特立独行的,它添加删除事件处理程序的方法分别是:

attachEvent() 和 detachEvent()
复制代码

同样需要有“事件名”和处理函数两个参数,但跟addEventListener()的区别是:

  • 事件名称需要加“on”,比如“onclick”;
  • 没了第三个布尔值,IE8及更早版本只支持事件冒泡;
  • 仍可添加多个处理程序,但触发顺序相反。

还有一点需要注意,DOM0和DOM2级的方法,其作用域都是在其所依附的元素当中,attachEvent()则是全局,即如果像之前一样使用this.id,访问到的就不是button元素,而是window,就得不到正确的结果。

那么,跨浏览器添加事件怎么写呢?这类代码通常具有通用性,所以可以将它封装成一个对象以备多人多项目复用,代码如下:

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;
        }
    }
}
复制代码

可明显看出,其使用了条件判断来检测浏览器是否具备那个方法,如果有,就用,没有,向更古老和通用的方法回溯。

怎么使用它呢?就像这样

EventUtil.addHandler(btn,"click",handler);
EventUtil.removeHandler(btn,"click",handler);
复制代码

小结

至此,JS事件的添加方法以及怎样做兼容就大概介绍完了,这只是事件的一个方面,也已有不少内容。

在现今JS框架满天飞的时代,从较早的JQ到较近的React、Vue,我们似乎很少需要再手动书写原生方法,它们本身封装的方法替我们省去了很多重复繁杂的劳动,但去了解和学习这些知识仍是有好处的。

JS总体的知识点可谓相当庞杂,但再庞杂的东西都是由小的点组成,把它的要点和脉络抽出,进行个个击破,学习的过程就会显得轻松愉快,最终绘成一张大的版图。

欲知后事如何,我们下回继续。

转载于:https://juejin.im/post/5b8a5f62f265da431e7b9477