createjs中on和addEventListener的区别

  • 内容
  • 评论
  • 相关

最近在帮群友解决问题的时候,无意中发现了on的一些特性,这让我好奇的打开了源码,结果发现on这个api大有文章。

大家都知道我写代码几乎不用on,都是addEventListener,不仅是flash遗留下的习惯,而是我当初认为on是类似于原生的onclick,onload这些方法,addEventListener是对它们的封装,用起来会更科学。其实不仅是我,大多数非前段转做createjs的人都不会去用on,而是用addEventListener。直到最近我打开了on的源码,发现createjs的on并不是原生的on,createjs的on才是对addEventListener的二次封装,用了7年多了才发现,看来源码还是要经常看的(其实文档上也有提,但是提的不多没重视,主要adobe也在用addEventListener)。既然是二次封装肯定多了一些功能和特性,而且会比addEventListener好用很多,那么我接下来写几个demo测试一下:

首先在原生那种addEventListener和on的写法:

var btn = document.getElementById("btn");
btn.onclick = function (){
    console.log(this)//this都是btn标签
}
btn.addEventListener("click",function (){
    console.log(this)//this都是btn标签
})

这里的this都是click对象的本身也就是btn,并且onclick会被覆盖addEventListener不会。

让我们再来看createjs中的写法:

var shape = new createjs.Shape();
shape.graphics.beginFill('#ff0000').drawRect(0,0,200,100).endFill();
shape.x = 100;
shape.y = 100;
stage.addChild(shape);
shape.addEventListener("click",function (){
  console.log(this)//this为window
})
shape.on("click",function (){
  console.log(this)//this为shape
})

在这里addEventListener方法中的this变成了window,而且on的this继承了原生的特性,this为侦听对象。

但是这些this其实都不是我们想要的,一般程序员想要的this是只想当年文本的作用域,那么我们先来看看之前addEventListener是如何修改this的

方法1:

var _this = this;
shape.addEventListener("click",function (){
  console.log(_this )
})

这是常用方法之一,但是如果嵌套多了,命名会非常复杂难懂,而且不优雅

方法2:

function clickHandler()
{
  console.log(this)
}
shape.addEventListener("click",clickHandler.bind(this))

常用方法之一,这样this会指向当前作用域,但是这样就无法remove了。

方法3:

shape.addEventListener("click",()=>{
  console.log(this);
})

es6新增的箭头函数,现在最常用的方法,但是问题跟上面一样无法remove了。

综上所述,上面的方法都不完美,所以我们一般用addEventListener都用下面的方法。

方法4:

function clickHandler()
{
  console.log(this);
}
var _clickHandler = clickHandler.bind(this);
shape.addEventListener("click",_clickHandler);
shape.removeEventListener("click",_clickHandler);

大家可以看到方法4是对方法2bind的一个扩展,放到一个变量里使其可以正常的remove,看起来还是略微复杂,有没有更简单的方法呢,有哪就是用on

方法on:

var Soul = Soul||{};
(function() {
    function TestContainer(){
        this.Container_constructor();
        let shape1 = new createjs.Shape();
        shape1.graphics.beginFill('#ff0000').drawRect(0,0,200,100).endFill();
        shape1.x = 100;
        shape1.y = 100;
        this._offBack = shape1.on("click",this.clickHandler,this);
        this.addChild(shape1);
        // shape1.off("click",this._offBack)//取消侦听
    }
    var p = createjs.extend(TestContainer,createjs.Container);
    p.clickHandler = function ()
    {
        console.log(this)//this为TestContainer
    }
    Soul.TestContainer = createjs.promote(TestContainer, "Container");
}());

为了区分windows我把他封装进一个TestContainer里,这时候this变成了想要的TestContainer,是怎么做到这点的呢,就是on的第三个参数,我们把那时候的this穿进去,就得到了想要的this(也可以换成别的想要的this)。想要去除侦听也只要shape1.off("click",this._offBack)就可以了,所以其实简化一下,代码就只有以下这点:

function clickHandler()
{
  console.log(this);
}
var _offback = shape.on("click",_clickHandler,this);
shape.off("click",_offback );

可以看到代码还是少了一些的,如果做多个侦听代码量精简的还要明显一些(起码on只要2个字母……)。

但是on的作用仅仅是可以切换this的指向吗?不,还有别的功能,我给大家看一下别的参数:

QQ图片20230106160051.png

和addEventListener一样的我就不介绍了,讲一下第三四五个参数:

第三个参数 scope:

也就是上面讲的this的作用域,默认为侦听对象,也就是跟原生一样,但是一般程序员习惯性为当前作用域,所以我们一般传this进去就好了。

第四个参数 once:

参数为true时方法触发一次即取消侦听,有什么用呢?主要用在类似于加载完成这种只触发一遍的方法,触发后我们就不用手动取消侦听了。(反正只触发一遍为什么要取消侦听?答案:为了垃圾回收,为了不内存泄漏,详细自己百度)

第五个参数 data:主要为了给function带参数进去,不过一般用不着,一般我们会直接放到变量里,如果侦听的对象多但方法在同一个里面,我们会直接把参数放到侦听对象,然后用event.currentTarget.xxx获取,这样就直接可以根据对象获取不同参数,甚至if else都不用,当然现在的话直接用on的第五个参数也可以了。

最后讲一下总结,on基本可以替代addEventListener了,我自己也在考虑已经封装好的一些代码要不要改掉(算了没时间,有新代码封装的时候写在新的代码里吧,反正addEventListener也用习惯了,大家也看习惯了)

111.png

评论

0条评论

发表评论

电子邮件地址不会被公开。