Zepto 是一个轻量级的针对现代高级浏览器的 JavaScript 库,是一个简化版的jQuery,简化了jQuery里很多的浏览器兼容性代码,主要针对移动端开发,它与 jquery 有着类似的 api。 如果你会用 jquery,那么你也会用 Zepto。
1.整体结构
首先,使用模块模式,先创建了一个全局的变量 Zepto,并将它指向一个匿名的自执行函数的返回值,不会污染其它的全局变量,如下
var Zepto = (function() {
})();
window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);
Zepto对象的定义就在这个立即调用函数里面,接下来把Zepto赋值给window:window.Zepto = Zepto。然后进行$变量名的冲突处理,如果$全局变量还没有定义,就将Zepto对象赋值给$全局变量。
把Zepto和$绑定到window下,就可以用Zepto(xxx)或者$(xxx)了。
if ( typeof define === "function" && define.amd ) {
define( "zepto", [], function () { return Zepto; } );
}
加入以上代码,能让 zepto 支持模块化(requirejs)写法。
2.核心结构
在使用 zepto 的时候,我们常用 $ 去获取 dom ,而 dom 对象上与能调用各种方法,那么这是怎么实现的呢,$ 又从何而来。
先不关注zepto的具体逻辑实现,来看看 zepto 结构的核心部分,首先找到它的入口函数。
$ = function(selector, context) {
return zepto.init(selector, context)
}
像使用函数一般,将我们要操纵的dom当做一个参数传入 Zepto 中,然后返回一个 zepto 对象来使用,我们传入参数,zepto 就调用 zepto.init。
zepto.Z = function(doms) {
return new Z(doms)
}
zepto.init = function(doms) {
var doms = ['dom1','dom2','dom3'];
return zepto.Z(doms);
}
在以上init方法中,会获取到 dom 元素集合,这就创建了一个 zepto 集合对象,然后将集合交由 zepto.Z() 方法处理,而 zepto.Z 方法返回的是函数 Z 的一个实例。
function Z(dom, selector) {
var len = dom ? dom.length : 0
for (var i = 0; i < len; i++) {
this[i] = doms[i]
}
this.length = dom.length;
}
函数 Z 将 doms 展开,变成实例的属性,i 为对应 domObj 的索引,并且在此处设置实例的 length 属性。
$ = function() {
return zepto.init();
}
$.fn = {
constructor: zepto.Z,
method: function() {
return this;
}
}
从这里看出, $ 其实是一个函数,在 $ 身上又挂了很多属性和方法,而实现 $ 函数的核心是 zepto.init ,其实 $ 调用的就是 zepto.init 这个内部方法,zepto.init 最终返回的又是 zepto.Z 的结果。
$.fn是一个对象,它拥有 zepto 对象上所有可用的方法,如 addClass(), attr(),和其它方法。在这个对象添加一个方法,这样所有的 zepto 对象上都能用到该方法了。
如下是实现 zepto 里常用的index()方法的一个例子:
$.fn.index = function(element) {
return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
}
3.神奇的$与结构之谜
那么,$又是从何而来的,相信初接触很多人都会好奇吧,因为之前没有阅读过jQuery源码,所以我一直好奇$是怎么运作的。
上面也提到了$是一个函数名,相当于:
function abc () { console.log(123); };
abc();
// 控制台输出123
function $ () { console.log(456); };
$();
// 控制台输出456
然后把$挂载到window对象里面,
所以就可以在随意位置使用,
所以在控制台直接打$或者window.$都同样输出函数:
function (selector, context) {
return zepto.init(selector, context)
}
上面提到这个函数返回的是一个zepto对象的init初始化方法,
从这里就知道了,原来插件已经创建了zepto对象,
继续找zepto对象的init初始化方法,
init接受两个参数,这里实例化一个例子:
$("div").css("background-color","#369");
直接debug里面的东西,可以看到selector就是选择器
这里写了一些判断selector是什么,在上面的实例化里是个字符串
所以返回一个dom,用了别的方法qsa返回
接着看qsa方法里面的东西
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
)
这个函数有点恶心,第一眼就看晕了,后面慢慢看着回过神
捋捋这里弄清两个知识点就比较明朗了:
知识点一:节点类型
var type = node.nodeType;
| 常量 | 值 | 描述 |
|---|---|---|
| Node.ELEMENT_NODE | 1 | 一个 元素 节点,例如
和 。
|
| Node.DOCUMENT_NODE | 9 | 一个 Document 节点。 |
| Node.DOCUMENT_FRAGMENT_NODE | 11 | 一个 DocumentFragment 节点 |
知识点二:三元操作符
var firstCheck = false,
secondCheck = false,
access = firstCheck ? "Access denied" : secondCheck ? "Access denied" : "Access granted";
console.log( access ); // logs "Access granted"
多个三元操作符也是可能的(注:条件运算符是右结合):
ps:&&有函数的时候三元操作符判断为true
浙公网安备 33010602011771号