仿照jquery

如何封装一个js库
把封装的js库添加到自定义的接口(自定义对象)上
jquery的原理

封装函数

封装函数获取兄弟节点(ele)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function 获取兄弟节点(ele){
var parent = ele.parentElement;
var allChildren = parent.children;
var length = 0;
var 伪数组={length:length};
for(i=0;i<allChildren.length;i++){
if(allChildren[i] !== ele){
伪数组[length] = allChildren[i];
length++;
伪数组.length = length;
}
}
return 伪数组;
}
console.log( 获取兄弟节点(li4) );

封装函数添加或删除多个class(ele,classes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var classes = {'a':true,
'b':false,//false表示删除
'c':true
};
function 添加或删除多个class(ele,classes){
for(var key in classes){
if(classes[key]){
ele.classList.add(key);
}else {
ele.classList.remove(key);
}
}
}
添加或删除多个class(li5,classes);

代码优化

上面的代码可以优化为:

1
2
3
4
5
6
7
8
9
10
原始代码:
if(classes[key]){
ele.classList.add(key);
}else {
ele.classList.remove(key);
}
优化:
var method = classes[key] ? 'add' : 'remove';
ele.classList[method](key);

打开console控制台查看结果

JS Bin

命名空间

1
2
3
4
5
6
7
8
var stage = {}; // 或者 window.stage = {}
stage.获取兄弟节点 = 匿名函数; //添加到对象内
stage.添加或删除多个class = 匿名函数; //添加到对象内
var x = stage.获取兄弟节点(li4);
console.log(x);
stage.添加或删除多个class(li6,{'a':true,'b':false,'c':true});

JS Bin

这种方法每次都要使用stage.xxx(ele,其他参数)太麻烦了

把ele放在前面的方法

上面的方法每次使用都要在前面加上命名空间,比如stage.xxx(ele,其他参数),这样太麻烦了

如何达到以下效果,不使用命名空间:

1
2
ele.获取兄弟节点()
ele.添加或删除多个class({'a':true,'b':false,'c':true});

直接加到Node.prototype上

将封装的函数直接加到Node的公用属性(原型)Node.prototype上。
并且把传入的第一个参数去掉,函数体内改成this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Node.prototype.获取兄弟节点 = function {
var parent = this.parentElement;
var allChildren = parent.children;
var length = 0;
var 伪数组={length:length};
for(var i=0;i<allChildren.length;i++){
if(allChildren[i] !== this){
伪数组[length] = allChildren[i];
length++;
伪数组.length = length;
}
}
return 伪数组;
};
console.log( li7.获取兄弟节点() );// 此处this就是li7

【点击查看源码】

但是这种方法可能会污染Node的公用属性,因此不建议直接加到Node.prototype上

把封装的js库添加到自定义的接口上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var stage = function(node) {
return {
获取兄弟节点: function() {
var parent = node.parentElement;
var allChildren = parent.children;
var length = 0;
var 伪数组 = { length: length };
for (var i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== node) {
伪数组[length] = allChildren[i];
length++;
伪数组.length = length;
}
}
return 伪数组;
},
添加或删除多个class: function(classes) {
for (var key in classes) {
var method = classes[key] ? 'add' : 'remove';
node.classList[method](key);
}
}
}
};
/////////////////
console.log( stage(li3).获取兄弟节点() );
stage(li3).添加或删除多个class({ 'a': true, 'd': true });

JS Bin

完善封装的js库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function stage(node) {
if(typeof node === 'string'){//如果传入的是个字符串
node = document.querySelector(node);
}
return {
getSibings: function() {
var parent = node.parentElement;
var allChildren = parent.children;
var length = 0;
var 伪数组 = { length: length };
for (var i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== node) {
伪数组[length] = allChildren[i];
length++;
伪数组.length = length;
}
}
return 伪数组;
},
add_remove_classes: function(classes) {
for (var key in classes) {
var method = classes[key] ? 'add' : 'remove';
node.classList[method](key);
}
}
};
};
/////////////////
console.log( stage('#li3').getSibings() );
stage(li4).add_remove_classes({ 'red': true});
stage('ul>li:nth-of-type(2)').add_remove_classes({'red':true});

JS Bin

用$缩写(alias)

1
window.$ = stage;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var stage = function (node) {
var eles = {length: 0};
if (typeof node === 'string') { //如果传入的是个字符串
var temps = document.querySelectorAll(node);//临时变量是个伪数组
for(var i=0;i<temps.length;i++){
//把临时变量存到伪数组eles内
eles[i] = temps[i];
eles.length = temps.length;
}
}
//在eles里添加添加方法
eles.add_remove_classes = function(classes) {
for (var key in classes) {
var method = classes[key] ? 'add' : 'remove';
for (var j=0;j<eles.length;j++){
eles[j].classList[method](key);
}
}
};
//console.log(eles);
return eles;//!!!一定要return,不然stage()调用完的返回值是undefined
};
window.$ = stage;
/////////////////
stage('li')..add_remove_classes({'blue': true});
等同于:
$('li').add_remove_classes({'blue': true});

JS Bin

通过arguments.length区分获取or设置

1
2
3
4
5
6
7
8
9
.css('width') //获取宽度
.css('width', '100px') //设置宽度
jquery的源码通过arguments.lenth判断是获取or设置
if(arguments.length == 1){//如果只传1个参数
// 获取
} else {
// 设置
}

作业题

jQuery的原型(共用属性)是:jQuery.fn

1
2
3
$.fn === jQuery.fn === jQuery.prototype
$().__proto__ === $.prototype === jQuery.prototype


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$('div').addClass('red') // 可将所有 div 的 class 添加一个 red
$('div').setText('hi') // 可将所有 div 的 textContent 变为 hi
window.jQuery = function(node) {
var nodes = {
length: 0
};
if (typeof node === 'string') {
var temp = document.querySelectorAll(node);
for (var i = 0; i < temp.length; i++) {
nodes[i] = temp[i];
nodes.length = temp.length;
}
}
nodes.addClass = function(classs) {
for (var i = 0; i < nodes.length; i++) {
nodes[i].classList.add(classs);
}
};
nodes.setText = function(text){
for (var i = 0; i < nodes.length; i++) {
nodes[i].textContent = text;
}
};
return nodes;
};
window.$ = jQuery;
$('div').addClass('red');
$('div').setText('hi');

JS Bin

-------------本文结束感谢您的阅读-------------