起因
昨晚在慕课网的十天精通CSS3课程中,看到animation那一块时,突然想去张鑫旭博客看看他有没写一些用animation做的有趣的动画。结果看到了一个我之前很想做,但不知道怎么实现的效果。
这个效果描述起来有点难度。就是平时页面加载数据的时候可能会显示“加载中...”,我想实现的就是后面的那个“...”,如何能让他逐个显示,然后循环。
学了animation后,这个还是很好实现的。但张鑫旭的效果则多了加载时间太久时,会显示“超时”的提示语。关键代码如图,详细代码在这里。
这个很人性化啊。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);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。