javascript事件

444 阅读5分钟

背景

如今的前端圈堪比是娱乐圈,虽然火热程度不及当年,但是活跃程度还是很厉害的,各种技术令人眼花缭乱。从小程序到各种混合开发的解决方案,从vue,react到angular,从canvas到three.js甚至webgl,从cmd到nodejs,从gulp到webpack,各种技术让人眼花缭乱,感觉学不过来了有没有。其实这些技术我们只要朝着一个方向努力慢慢积累,总结就会慢慢成长的,无需跳过心急。

看法

自己平时总是把精力放在node,webpack之类的东西上,但是很多东西都需要查,其实后来才发现基础才是最重要的。我一直很看重基础的学习,虽然我js基础我很是不满意,哈哈,但是我会像大家一样一起学习,总结的,大家一起加油。最近在听 喜马拉雅app里面的 《陪你读书javacript》,不知道有没有一起,如果刚好有喜马拉雅,我推荐大家听一下,直接搜就行,老师比较系统的讲js,三个特别来形容吧,特别基础特别深奥特备有趣

注:我不是打广告的啊,我真的是听了他的课,来总结的只是点的,哈哈

事件流

  • 冒泡
  • 捕获

事件级别

  • dom0 HTML
  • dom2 属性事件
  • dom3 事件监听
dom0事件(html事件)
<div onclick="alert('1')"></div>

dom2事件(属性事件)

let dom = document.querySelector(".dom");
dom.onclick = function(){
    //执行代码
}

dom3事件(事件监听)

    let dom = document.querySelector(".dom");
    dom.addEventListener('click', function(){
        // 处理函数
    }, true);

addEventListender接受三个参数,第一个参数为 事件名称,如(click、mousedown),第二个为 事件对应的处理函数,第三个是 是否为事件捕获常用的是传一个 Boolean值(true表示在事件捕获阶段触发,false表示在事件冒泡阶段触发),也可以传一个对象,下面会详细讲解。

其实这些东西,js稍微有点基础的同学们,都应该经常用这些东西,我总结一下方便大家记得更深刻,哈哈。下面主要讲一下 addEventListener的几个参数。

先给一下基础的html结构

<div class="box">
	<div class="child"></div>
</div>

下面是javascript代码:


    let dom = document.querySelector(".dom");
    dom.addEventListener('click', function(){
        // 处理函数
    }, true);

    let box = document.querySelector('.box');
    let child = document.querySelector('.child');
    let boxEvent = function(){
    	console.log('box');
    }
    let childEvent = function(){
    	console.log('child');
    }
    
    box.addEventListener('click', boxEvent, true);
    child.addEventListener('click', childEvent, true);

这大家肯定都很了解,我就简单总结一下:

代码如上,我们点击了child。

  • 如果第三个参数为false(事件在冒泡阶段触发),那么控制台打印的顺序为child,box
  • 如果第三个参数为true(事件在捕获阶段触发),那么控制台打印的顺序为box,child
  • 注意:不管css怎么设置都不会影响事件的执行,比如 child通过css定位特别大,完全盖住了这个box,依然不会影响事件执行书序。

如果我们要取消事件监听把上面的addEventListener替换为removeEventListener即可,但是需要注意以下几点

  • 如果事件的处理函数用的不是函数名,而是匿名函数,则无论如何都无法取消这个事件,因为我们无法找这个函数的引用。
  • 事件的参数要对应,比如监听的是捕获时的事件(第三个参数为true)时,我们取消时也需要设置同样的值,反之亦然。

上面提到addEventListener第三个参数也可以是个对象,我们平时一般很少会用到(至少我是很少用),下面就给大家仔细介绍下以便一起记忆,看下面的代码:

    el.addEventListener(eventType, optionFunction, {
    capture: false, // 和直接把第三个参数填写布尔值一样,代表是否为捕获时触发事件
    once: false, // 默认fasle,是否只执行一次
    passive: false //默认为false,代表是否承诺浏览器不会调用e.preventDefault()来阻止默认行为
    })

对于addEventListener第三个参数里的passive,在多讲几句吧,如下:

  • 背景:对于一个事件监听,浏览器是不知道他会不会执行默认行为(比如滚动条等),所以浏览器只能等事件结束了才会执行默认行为,而很多情况下,我们是不会禁止行为的,但是没办法,我们没有给浏览器承诺,所以浏览器每次都需要等你执行完事件函数的东西才能知道你没有调用e.preventDefault(),然后才执行默认行为,这就造成了资源郎芬
  • 优点:对于一些我们不会阻止默认行为的情况,我们在监听函数的时候,设置了passive:true,浏览器就会提前知道你并不会使用e.preventDefault(),浏览器就会自己进行优化无需等事件处理函数执行完就可以执行默认行为,这样在有些极端情况下(比如处理特别频繁的事件中比如,touchmove,scroll)会提高很多的性能
  • 表现: 如果设置了passive:true,但是我们又设置了e.preventDefault()呢,亲测chrome浏览器下会报错,Unable to preventDefault inside passive event listener invocation.

关于event

event.targetevent.currentTarg区别

  • event.target: 返回触发事件的元素(在事件委托中用的就是target)
  • event.currentTarget: 返回绑定事件的元素

下面是我自己实现小型jq中的on方法( dom绑定事件)

一般情况下


    on(evtName, evtFunc, isCatch = true) {

        document.addEventListener(evtName, (e) => {
            this.domList.forEach(dom => {
                if (e.target == dom) {
                    evtFunc.call(e.target);
                }
            })
        }, isCatch);
    }
    

     $(".lala").on('click',function(){
      console.log(this);// 打印当前触发事件的元素
    })

如果上面的evtFunc.call(e.target);evtFunc.call(e.currentTarget);


    on(evtName, evtFunc, isCatch = true) {

        document.addEventListener(evtName, (e) => {
            this.domList.forEach(dom => {
                if (e.target == dom) {
                    evtFunc.call(e.currentTarget);
                }
            })
        }, isCatch);
    }
    

     $(".lala").on('click',function(){
      console.log(this);// 这里不管点击谁都打印  document了,因为是document绑定的事件
    })

总结

以上是我对js事件的一些总结,所有的代码都算是我直接在有道云敲的,没有用ide,入股哪里有写错的,还请大家给以友善的提醒,或者有些的不合适甚至错的地方,大家一起来纠正学习。