读zepto源码,封装自己的zepto库 (三)

本篇着重讲选择器$()选择器
本例我们主要修改wclimb.init=function(selector){}里面的代码
将wclimb.init代码修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var dom
if (!selector) return wclimb.Z()
else if (typeof selector == 'string') {
dom = wclimb.qsa(document, selector)
}
else if (typeof selector == 'function'){
return wclimb.ready(selector)
}
else{
if (isArray(selector)) {
dom = compact(selector)
}
else if (wclimb.isZ(selector)) return selector
else{
if (isObject(selector)) dom = [selector], selector = null ;
else dom=wclimb.qsa(document,selector)
}

}
return wclimb.Z(dom, selector)

  • 首先判断是否存在selector,如果不存在则直接return
  • 然后判断是否是字符串类型,如$('a b'),将选择的元素保存起来
  • 如果是函数则return wclimb.ready(selector)就是我们经常用的$(function(){})
  • 后面判断是否是当前对象的实例(用了isZ方法)还有判断是否是数组或对象

我们先在函数顶部添加如下

1
2
3
emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter
slice = emptyArray.slice
function compact(array) { return filter.call(array, function(item){ return item != null }) }

emptyArray = [],避免出现每次都重复创建的一个数组[]
然后拿到数组里面的方法
compact就是一个数组筛选,如果某个元素不存在$([1,2,,,4]);只会创建一个[1,2,4]的数组

wclimb.qsa方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
wclimb.qsa=function(element, selector){
var found,
maybeID = selector[0] == '#',
maybeClass = !maybeID && selector[0] == '.',
nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
isSimple = /^[\w-]*$/.test(nameOnly)

return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById
( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
(element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
slice.call(
isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName
maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
element.getElementsByTagName(selector) : // Or a tag
element.querySelectorAll(selector) // Or it's not simple, and we need to query all
)
}

这里我直接用了zepto的代码
wclimb.init=function(selector){}里的代码还使用了判断数据类型的代码isArray``isObject

判断数据类型

在函数外面添加如下代码来进行数据类型判断

1
2
3
4
5
6
7
8
9
10
11
12
// 判断类型
var obj_i={};
['Boolean', 'Number','String', 'Function', 'Array' ,'Date', 'RegExp', 'Object' ,'Error'].forEach(function(el,idx){
obj_i["[object " + el + "]"] = el.toLowerCase()
})
function type(obj) {
return obj == null ? String(obj) :
obj_i[Object.prototype.toString.call(obj)] || "object"
}
function isObject(obj) { return type(obj) == "object" }
function isArray(obj) { return type(obj) == "array" }
function isString(obj) { return type(obj) == "string" }

wclimb.ready函数

在外面设置如下函数

1
2
3
4
5
6
wclimb.ready = function(fn) {
document.addEventListener('DOMContentLoaded',function() {
fn && fn();
},false);
document.removeEventListener('DOMContentLoaded',fn,true);
};

wclimb.isZ函数

下面代码判断object是不是wclimb.Z的实例

1
2
3
wclimb.isZ = function(object) {
return object instanceof wclimb.Z
}

现在试试代码吧,我们顺便把addClass里判断hasClass代码注释去掉了

1
2
3
4
5
6
7
8
9
10
11
12
<script>
// ready
$(function(){
alert(1)
})
// addClass
$('p').addClass('a b')
// 实例
console.log($(this))
// 数组
$([1,23,3,,4])
</script>

全部代码

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
(function(){

var wclimb = {},$
emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter
slice = emptyArray.slice
function compact(array) { return filter.call(array, function(item){ return item != null }) }

$ = function(selector){
return wclimb.init(selector)
}

wclimb.init = function(selector){
var dom
if (!selector) return wclimb.Z()
else if (typeof selector == 'string') {
dom = wclimb.qsa(document, selector)
}
else if (typeof selector == 'function'){
return wclimb.ready(selector)
}
else{
if (isArray(selector)) {
dom = compact(selector)
}
else if (wclimb.isZ(selector)) return selector
else{
if (isObject(selector)) dom = [selector], selector = null ;
else dom=wclimb.qsa(document,selector)
}

}
return wclimb.Z(dom, selector)

}
wclimb.Z = function(dom,selector){
return new Z(dom,selector)
}

function className(node, value){
var klass = node.className || ''

if (value === undefined) return klass
node.className = value
}

wclimb.Z.prototype = Z.prototype = {
each:function(callback){
[].every.call(this, function(el, idx){
return callback.call(el, idx, el) !== false
})
return this;
},
addClass:function(name){
if (!name) return this
return this.each(function(el,idx){
if (!('className' in this)) return
classList = [];

var cls = className(this)

name.split(/\s+/g).forEach(function(klass){

if (!$(this).hasClass(klass))
classList.push(klass)

}, this)

classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))

})
},
hasClass : function(cls) {
var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
for (var i = 0; i < this.length; i++) {
if (this[i].className.match(reg)) return true;
return false;
}
return this;
}
}
wclimb.ready = function(fn) {
document.addEventListener('DOMContentLoaded',function() {
fn && fn();
},false);
document.removeEventListener('DOMContentLoaded',fn,true);
};

wclimb.qsa=function(element, selector){
var found,
maybeID = selector[0] == '#',
maybeClass = !maybeID && selector[0] == '.',
nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
isSimple = /^[\w-]*$/.test(nameOnly)

return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById
( (found = element.getElementById(nameOnly)) ? [found] : [] ) :
(element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :
slice.call(
isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName
maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class
element.getElementsByTagName(selector) : // Or a tag
element.querySelectorAll(selector) // Or it's not simple, and we need to query all
)
}

function Z(dom,selector) {
for (var i = 0; i < dom.length; i++) {
this[i] = dom[i]
}
this.selector = selector;
this.length = dom.length
}
wclimb.isZ = function(object) {
return object instanceof wclimb.Z
}
// 判断类型
var obj_i={};
['Boolean', 'Number','String', 'Function', 'Array' ,'Date', 'RegExp', 'Object' ,'Error'].forEach(function(el,idx){
obj_i["[object " + el + "]"] = el.toLowerCase()
})
function type(obj) {
return obj == null ? String(obj) :
obj_i[Object.prototype.toString.call(obj)] || "object"
}
function isObject(obj) { return type(obj) == "object" }
function isArray(obj) { return type(obj) == "array" }
function isString(obj) { return type(obj) == "string" }

window.$ = window.wclimb = $

})()
坚持原创技术分享,您的支持将鼓励我继续创作!