zoukankan      html  css  js  c++  java
  • 偶遇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,再改改吧

  • 相关阅读:
    GDAL并行IO的疑问
    memcpy一段内存到std::vector<double>
    解决mysql无法远程登陆问题
    .net 上传word 转为 html
    OnCheckedChanged的触发需要AutoPostBack="true"
    asp.net与word文档在线
    [转]mysql如何设置主键和外键,实现级联更新、级联删除
    asp.net 读取Word
    datalist 嵌套 datalist 中的table 乱
    [转]php中使用ignore_user_abort()函数后,如何停止后台运行的程序?
  • 原文地址:https://www.cnblogs.com/pssp/p/6206785.html
Copyright © 2011-2022 走看看