起因

昨晚在慕课网的十天精通CSS3课程中,看到animation那一块时,突然想去张鑫旭博客看看他有没写一些用animation做的有趣的动画。结果看到了一个我之前很想做,但不知道怎么实现的效果。

这个效果描述起来有点难度。就是平时页面加载数据的时候可能会显示“加载中...”,我想实现的就是后面的那个“...”,如何能让他逐个显示,然后循环。

学了animation后,这个还是很好实现的。但张鑫旭的效果则多了加载时间太久时,会显示“超时”的提示语。关键代码如图,详细代码在这里

clipboard.png

这个很人性化啊。js代码也很少。但问题来了,就几行代码,我却没看懂。。。
1.为什么用bind,不是都用on的吗?bind和on有啥区别
2.setTimeout()为什么绑定的函数后面要用.bind(this)

jQuery中bind和on的区别

都是用于绑定事件。如果绑定的元素已存在,那么用哪个都可以,没有区别。

注意了,是在所绑定的这个元素已经存在的前提下,两者无区别。
那如果这个元素原本是没有的,需要点击一个按钮,才动态生成呢?

我们看下jQuery文档中bind和on绑定事件的语法:

.bind(events [,eventData], handler)

.on(events [,selector] [,data], handler)

从语法中可以看到,.on方法比bind多了一个参数'selector'。

其作用是筛选出调用.on方法的dom元素的指定子元素,最常用的情景就是,一个ul列表,我需要点击“添加li”按钮后,在ul列表最后增加一个li。如下:
$('ul').on('click','li',function(){console.log('click');});

因此,.on方法的好处就在于当我用

$('ul').append('<li>我是新增的li</li>');

来动态生成新的li时,.on方法能对其这个新生成的元素绑上click事件。而.bind方法则不行,因为它的语法中没有提供'selector'这个参数。

.on方法的这个好处就是传说中的事件委托。将对某子元素的事件委托给其父元素,当点击子元素时,由于事件冒泡原理,会向上一级(即父元素)冒泡,就触发了我们用.on方法绑定在父元素的事件。

setTimeout中的this指向

因为感觉setTimeout里面有很多坑,所以对setTimeout很陌生。
一查才知道setTimeout传入函数时,函数中的this指向window对象。如下:

var num = 0;
function Obj (){
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(this.num);
        }, 1000)
    }
}
var obj = new Obj; 
obj.getNum();//1  打印的是obj.num,值为1
obj.getNumLater()//0  打印的是window.num,值为0

可以看到setTimeout中函数内的this是指向了window对象。因为setTimeout()调用的代码运行在与所在函数完全分离的执行环境上,导致这些代码中包含的 this 关键字会指向 window (或全局)对象。详细可以看MDN setTimeout

用bind纠正setTimeout中this指向

刚开始我以为这个bind和前面提到的bind是同一个bind。后来看了下MDN bind才发现是不同的。

它是Function.prototype的一个内置方法,之前提到的bind是jquery绑定事件的一个方法。

bind语法:bind(this.args,arg1[, arg2[, ...]]])
后面那段参数可能看得有点晕,没关系,现在只要用第一个参数就好了。

看回张鑫旭那段代码中setTimeout写法

setTimeout(function() {
        this.ajaxing = false;
        this.innerHTML = "提交超时";
}.bind(this), 30000);

首先要清楚当前的this指的是所要点击的a元素。

当setTimeout中的函数执行时,bind会创建一个新函数,bind的第一个参数会作为新函数运行时的this指向,所以原本指向window的this就改为指向了当前这个this,即指向了这个a元素。

其他方法

改变setTimeout中this指向还有两种方法。一种是闭包,将this存到一个变量中,setTimeout中函数内部访问这个新的变量,就能得到当前的对象。改写一下上面的代码,如下:

$("#submit").bind("click", function() {
    if (!this.ajaxing) {
    var that = this;
        this.ajaxing = true;
        this.innerHTML = '提交订单中<span class="ani_dot">...</span>';
        setTimeout(function() {
            that.ajaxing = false;
            that.innerHTML = "提交超时";
        }, 30000);
    }
});

还有一种方法是用箭头函数,直接改写下setTimeout即可

setTimeout(()=>{
        that.ajaxing = false;
        that.innerHTML = "提交超时";
}, 30000);

参考

jquery的bind跟on绑定事件的区别
关于setInterval和setTImeout中的this指向问题


gyt95
139 声望8 粉丝

“那个写页面的”。


引用和评论

0 条评论