偶遇this之坑

前言

在写一个懒加载插件时,遇到一个坑,就是this的指向问题,我想这种情况大部分人都会遇到,就写下来,新手也有个参考。

事件

有些页面图片比较多,但用户还不一定会全看,这样的话,全部去加载这些图片,就有点浪费资源了,于是想写一个通用的插件来解决这个问题

想法

根据滚动条高度加屏幕高度来判断是否加载这张图片,需要懒加载的图片这样写

<img data-src="image/bg.jpg">

凡是加上这个属性的都会做懒加载处理。

this之坑

以下是最终的代码

function SetImg(top){
    var imgs = Array.prototype.slice.apply(document.getElementsByTagName("img"));
    this.imgs = imgs.filter(function(item,index){
        return item.dataset.src;
    });
    this.top = top || 150;
}
SetImg.prototype = {
    init:function(){
        this.event();
    },
    setSrc:function(){
        if(this.imgs.length===0){
            window.removeEventListener("scroll",this.setSrc);
        };
        var _this = this;
        this.imgs.forEach(function(item,index){
            if(document.documentElement.clientHeight+document.body.scrollTop+_this.top>item.offsetTop||item.offsetTop<document.documentElement.clientHeight){
                item.src = item.dataset.src;
                _this.imgs.splice(index,1);
            }
        })
    },
    event:function(){
        this.setSrc = this.setSrc.bind(this);
        window.addEventListener("load",this.setSrc);
        window.addEventListener("scroll",this.setSrc);
    }
};
new SetImg().init();

这个代码已经解决了this的指向问题,也就是下面这句

this.setSrc = this.setSrc.bind(this);

一开始是没有这句话的,但问题是,我在setSrc里面使用了this,而恰恰那里面的this指向的是window,为什么指向window?因为这句话

window.addEventListener("load",this.setSrc);
window.addEventListener("scroll",this.setSrc);

我们说this始终指向一个对象,而现在给添加的事件,就是在window身上添加的,正如

element.addEventListener("click",fn);

这句不就是指向element吗,那上面的那个指向window,也就不足为奇了。因此这也是为什么最后我添加这么一句

this.setSrc = this.setSrc.bind(this);

其实一开始我没想要这么做,但这也是迫不得已的事,一开始我是这样写的:

window.addEventListener("load",this.setSrc.bind(this));
window.addEventListener("scroll",this.setSrc.bind(this));

但这样的问题是,bind返回的是一个新对象,而不是原本的this.setSrc。一般情况下,这也不是什么大问题,但坑就坑在this.setSrc里面的这句

if(this.imgs.length===0){
    window.removeEventListener("scroll",this.setSrc);
};

看似一切都正常,但这是一个大坑,这里面的this.setSrc指向的是SetImg.setSrc,而

window.addEventListener("scroll",this.setSrc.bind(this));

this.setSrc.bind(this)这是一个新对象,因此你根本就无法remove掉这个新对象。所以最终才想出个迫不得已的方法就是让this.setSrc变成新的那个对象。

可能有些朋友,不太懂为什么要写这么一句:

if(this.imgs.length===0){
    window.removeEventListener("scroll",this.setSrc);
};

这句话的作用是,如果所有图片都加载完毕了,这个滚动事件,就不需要了。当然如果你直接使用window.onscroll这种情势来写,或许这个问题可以很好的解决,但作为一个插件用addEventListener是迫不得已的,因为我不知道哪个页面使用了onscroll事件,如果我直接那样写,就会把其他人写的事件覆盖掉。

结语

这种情况出现的概率还是蛮高的,导致这种问题的出现就是,事件里面的this和构造函数里面的this,指向的是不同的对象,所以啊这就是坑点。

说到正题,这个插件还不能用T_T,再改改吧

转载于:https://www.cnblogs.com/pssp/p/6206785.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值