写在最前面:
这种技术包含两个部分:一个是创建代表HTML元素的对象工厂(其实就是获取THML元素的方法,在工厂模式中会讲),另一个就是一些可以操作HTML元素的方法。当然上面说的不清晰也没有关系,文章很短,希望各位朋友看完一定有新发现。
正文:
先来个简单的jquery例子:
$('.box').find('.box2').siblings('.box2').css({'color':'red','border:1px solid green'});
为什么可以通过点( . )来实现链式调用,先思考一下什么可以通过点(.)来操作。没错,是对象。有了对象就可以通过点( . )来调用其中的属性。而jquery正式通过点(.)来调用上一步操作中返回的对象,从而实现链式调用。
既然知道的原理,就来写写试试。既然是每次操作返回的都是当前对象,可以尝试用this来指代当前对象。
现在向我们自己的方法库添加一些方法:
//通过在Function的原型上扩展一个添加方法的方法
//并return this 使得返回当前对象,从而实现链式调用
Function.prototype.addMothed = function(mothedName, mothed) {
this[mothedName] = mothed;
return this;
};
(function() {
function myMothed() {
console.log('主方法');
}
//通过链式调用不断添加方法
myMothed.addMothed('mothed1', function() {
console.log('方法1');
}).addMothed('mothed2', function() {
console.log('方法2');
}).addMothed('mothed3', function() {
console.log('方法3');
})
myMothed();//主方法
myMothed.mothed1();//方法1
myMothed.mothed2();//方法2
myMothed.mothed3();//方法3
})()
确实成功的向我们自己的方法库中通过链式调用的方法添加了一些方法,并且成功调用,但是看起来没啥鸟用。那我们就换个角度看:
//通过在Function的原型上扩展一个添加方法的方法
//并return this 使得返回当前对象,从而实现链式调用
Function.prototype.addMothed = function(mothedName, mothed) {
this.prototype[mothedName] = mothed;
return this;
};
(function() {
function MyMothed(num) {
this.num = num;
}
//通过链式调用不断添加方法
MyMothed.addMothed('mothed1', function() {
console.log(this.num+1);
return this;
}).addMothed('mothed2', function() {
console.log(this.num+2);
return this;
}).addMothed('mothed3', function() {
console.log(this.num+3);
return this;
})
//工厂函数
window.$ = function(num){
return new MyMothed(num);
}
//和上面不一样的是每个方法下面都有一个return this
//使我们可以通过链式调用每个方法返回的元素
//下面使用我们的方法
$(10).mothed1().mothed2().mothed3();// 11 12 13
})()
这样的理解是不是更近了一步,通过链式调用添加方法,在通过链式调用使用方法。在看一个实际一点的例子,通过链式调用操作DOM。
<div id="box"></div>
Function.prototype.addMothed = function (mothedName, mothed) {
this.prototype[mothedName] = mothed;
return this;
};
(function () {
function _$(els) {
this.box = document.getElementById(els);
}
//通过链式调用不断添加方法
_$.addMothed('setWidth', function (val) {
console.log(this);
this.box.style.width = val;
return this;
}).addMothed('setHeight', function (val) {
this.box.style.height = val;
return this;
}).addMothed('setBackground', function (val) {
this.box.style.backgroundColor = val;
return this;
})
window.$ = function (els) {
return new _$(els);
}
$('box').setWidth('100px').setHeight('100px').setBackground('red');
})()
没错我们就得到了一个长宽为100px,背景是红色的正方形。
现在我们要考虑一个问题,如果我用$表示现在的这个可以链式调用的方法,但是又引用了jquery库,那么就会被我们的方法覆盖,怎办办? 我们可以像下面的方法来绑定版本,或者说更新版本,只需要改其中的一小段代码。
window.$ = function (els) {
return new _$(els);
}
//修改为
window.installVersion =function(scope,interface){
scope[interface] = function(els){
return new _$(els);
}
}
//这样使用
installVersion(window,'$');
最后一个关键技巧是通过回调从链式调用中获取数据。
先看一个例子:
//有一个动物园,每天的流程是吃饭,做游戏,睡觉 还有一个查看开不开心的方法
(function () {
function Zoom(animal) {
this.animal = animal;
this.mood = false;
}
Zoom.prototype = {
constructor: Zoom,
eat: function (fruit) {
console.log(this.animal + '今天吃了' + fruit);
return this;
},
play: function (toy) {
console.log(this.animal + '今天玩了' + toy);
this.mood = true;
return this;
},
sleep: function () {
console.log(this.animal + '睡觉了');
return this;
}
}
window.zoom = function (animal) {
return new Zoom(animal);
}
function checkMood(){
console.log(this.mood);
}
var dog = zoom('dog');
dog.eat('苹果').play('秋千').sleep();//dog今天吃了苹果 --> dog今天玩了秋千 --> dog睡觉了
//如果现在要求玩过之后必须要查看开不开心才能睡觉
dog.eat('苹果').play('秋千');
checkMood.call(dog);
dog.sleep();
})()
这种取值的方法就回切断链式调用,所以我们要通过回调的方法来取值,下面是改写的方法:
(function () {
function Zoom(animal) {
this.animal = animal;
this.mood = false;
}
Zoom.prototype = {
constructor: Zoom,
eat: function (fruit) {
console.log(this.animal + '今天吃了' + fruit);
return this;
},
play: function (toy,callback) {
console.log(this.animal + '今天玩了' + toy);
this.mood = true;
callback.call(this);
return this;
},
sleep: function () {
console.log(this.animal + '睡觉了');
return this;
}
}
window.zoom = function (animal) {
return new Zoom(animal);
}
function checkMood(){
console.log(this.mood);
}
var dog = zoom('dog');
dog.eat('苹果').play('秋千',checkMood).sleep();//dog今天吃了苹果 --> dog今天玩了秋千 --> ture --> dog睡觉了
})()