zepto学习之路--核心函数$()的实现
$()可以说是jquery的精华了,为dom操作带来了极大的灵活和方便。zepto号称“移动版的jquery”,那么它是怎么来实现这个核心函数呢?我们来详细探讨下。
1、首先,我们看下zepto中它是怎么定义的:
$ = function(selector, context) {
return zepto.init(selector, context)
}
这里很明显,如果你试图通过S(“”)来获取一个dom元素,zept会将其封装为一个zepto对象返回给你,那么zepto.init是如何实现的呢?
2、zepto.init
zepto.init = function(selector, context) {
// If nothing given, return an empty Zepto collection
if (!selector) return zepto.Z() //没有参数,返回空数组
//如果selector是个函数,则在DOM ready的时候执行它
else if (isFunction(selector)) return $(document).ready(selector)
//如果selector是一个zepto.Z实例,则直接返回它自己
else if (zepto.isZ(selector)) return selector
else {
var dom
//如果selector是一个数组,则将其里面的null,undefined去掉
if (isArray(selector)) dom = compact(selector)
//如果selector是个对象,注意DOM节点的typeof值也是object,所以在里面还要再进行一次判断
else if (isObject(selector))
//如果是申明的对象,如{}, 则将selector属性copy到一个新对象,并将结果放入数组
//如果是该对象是DOM,则直接放到数组中
dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null
//如果selector是一段HTML代码片断,则将其转换成DOM节点
else if (fragmentRE.test(selector)) dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
//如果存在上下文context,则在上下文中查找selector,此时的selector为普通的CSS选择器
else if (context !== undefined) return $(context).find(selector)
//如果没有给定上下文,则在document中查找selector,此时的selector为普通的CSS选择器
else dom = zepto.qsa(document, selector)
//最后将查询结果转换成zepto集合
return zepto.Z(dom, selector)
}
}
在这里zepto.innit函数根据输入参数的情况来进行不同的操作,如果你输入的参数是标准的(selector,context)的形式,其会调用zepto.qsa也就是dom查询函数,最后最后将得到的元素数组用zepto.z()函数包装成zepto对象数组返回。所以这个函数的包括两个过程:一、查找生成满足条件dom元素数组;二、将dom元素包装成zepto对象,这样返回的对象就具有了zepto的方法。ok,我们继续分解这两个过程:
3、zepto.qua()
zepto.qsa = function(element, selector) {
var found
//当element为document,且selector为ID选择器时
return (isDocument(element) && idSelectorRE.test(selector)) ?
//直接返回document.getElementById,RegExp.$1为ID的值,当没有找节点时返回[]
((found = element.getElementById(RegExp.$1)) ? [found] : []) :
//当element不为元素节点或者document时,返回[]
(element.nodeType !== 1 && element.nodeType !== 9) ? [] :
//否则将获取到的结果转成数组并返回
slice.call(
//如果selector是标签名,直接调用getElementsByClassName
classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) :
//如果selector是标签名,直接调用getElementsByTagName
tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) :
//否则调用querySelectorAll
element.querySelectorAll(selector))
}
ok,你没看错,这就是zepto的核心dom查找函数,其思想是先用正则表达式判断selector的类型,然后调用相应的方法。对于不是单一类型的选择符,最后用querySelectorAll()函数来进行查询,并且用slice将得到的元素集合转化为数组。这里因为面向移动端,所以也没有考虑queryselectall的兼容性。在这里附带一点,在ie6,7中是不支持queryselectorall方法的,有人提出了一种补充的方法来解决兼容性:
if (!document.querySelectorAll) {
document.querySelectorAll = function (selectors) {
var style = document.createElement('style'), elements = [], element;
document.documentElement.firstChild.appendChild(style);
document._qsa = [];
style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
window.scrollBy(0, 0);
style.parentNode.removeChild(style);
while (document._qsa.length) {
element = document._qsa.shift();
element.style.removeAttribute('x-qsa');
elements.push(element);
}
document._qsa = null;
return elements;
};
}
if (!document.querySelector) {
document.querySelector = function (selectors) {
var elements = document.querySelectorAll(selectors);
return (elements.length) ? elements[0] : null;
};
}
// 用于在IE6和IE7浏览器中,支持Element.querySelectorAll方法
var qsaWorker = (function () {
var idAllocator = 10000;
function qsaWorkerShim(element, selector) {
var needsID = element.id === "";
if (needsID) {
++idAllocator;
element.id = "__qsa" + idAllocator;
}
try {
return document.querySelectorAll("#" + element.id + " " + selector);
}
finally {
if (needsID) {
element.id = "";
}
}
}
function qsaWorkerWrap(element, selector) {
return element.querySelectorAll(selector);
}
// Return the one this browser wants to use
return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;
})();
4、zepto.z()
在找到dom元素数组后,剩下的就是将其封装成zepto对像。
zepto.Z = function(dom, selector) {
dom = dom || []
dom.__proto__ = $.fn //通过给dom设置__proto__属性指向$.fn来达到继承$.fn上所有方法的目的
dom.selector = selector || ''
return dom
}
没错,这个Z函数就是包装函数,短小而强悍。zepto处理的方法及其剪短,通过将$.fn赋给dom的__proto__属性,来继承fn的属性,这也就意味着这一步后,你同过$()方法得到的元素都拥有了fn中的方法。进而链式调用也就实现了。。。
zepto学习之路--核心函数$()的实现的更多相关文章
- zepto学习之路--数组去重和原生reduce
好吧开始读zepto的源代码,最前面给处理trim和reduce的原生实现,感觉写的很紧凑,其中reduce写的有点晦涩,个人感觉还不错.主要zepto的作者是无分号党,看起了有点不习惯. 3 if ...
- zepto学习之路--源代码提取
最近在看zepto的源代码,把一些有用的函数摘出来,看看zepto是怎么实现的,自己做的时候也可以用.说实话,zepto的实现有一些看起来还是很晦涩的,可能是自己的水平不够,看不透作者的真正的意图. ...
- MySql 学习之路-Date函数
MySQL中重要的内建函数 函数 描述 NOW() 返回当前的日期和时间 NOW() 返回当前的日期和时间. 语法 NOW() -- 实例 -- 下面是 SELECT 语句: SELECT NOW() ...
- MySql 学习之路-聚合函数
下面是mysql 数据库中经常用到的聚合函数的简单实例 -- 创建学生表 create table student ( id int primary key auto_increment commen ...
- Python学习之路5 - 函数
函数 定义方式: def func(): "这里面写函数的描述" 这里写代码 return x #如果没有返回值就叫"过程",函数和过程的区别就是有无返回值 实 ...
- Webwork 学习之路【03】核心类 ServletDispatcher 的初始化
1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...
- jQuery学习之路(1)-选择器
▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...
- spring源码学习之路---AOP初探(六)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 最近工作很忙,但当初打算学习 ...
- [EntLib]微软企业库5.0 学习之路——第一步、基本入门
话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...
随机推荐
- 笔记一:OOAD与UML
一.面向对象的概念与方法 1. 面向对象 1.1. 面向对象是一种系统建模技术 1.2. 面向对象编程是按照OO的方法学来开发程序的过程 1.3. 通过分析系统内对象的交互来描述或建模一个系统 1. ...
- qsort函数辅助函数compare函数的编写
qsort的第四个参数,辅助函数compare的关于不同排序对象的不同写法: 一.对int类型数组排序 ]; int compare(const void *a, const void *b) { r ...
- The type java.util.Map$Entry cannot be resolved. It is indirectly referenced from required .class files
JDK版本的问题. 解决方法: 原来jdk1.8不向下兼容,用回1.6的就可以了. 下图有三个jdk,前两个自己装的,第三个MyEclipse自带的.
- HeapSpray初窥(2014.12)
注:环境是xp+ie8 1.HeapSpray简介 Windows的堆因为动态分配和释放的特点,其看起来是不连续(没有规律的),但是仍可以找到一定的规律:大量的连续分配会更倾向使用连续的地址,减少了碎 ...
- Python学习之旅--第一周--初识Python
一:Python是一种什么样的语言? 1.语言的分类: a.编译型语言和解释性语言: 通常所说的计算机语言分为编译型和解释型语言.编译型语言典型的如C,C++,通常在程序执行之前必须经由编译器编译成机 ...
- 安装、配置、启动FTP、SSH或NFS服务
(1)准备使用软件维护工具apt-get. Ubuntu7.10中没有安装FTP.SSH.NFS服务器软件,它提供了一个很方便的安装.升级.维护软件的工具apt-get.apt-get从光盘.网络上下 ...
- 【bug】Unable to execute dex: Multiple dex files define
This is a build path issue. Make sure your bin folder is not included in your build path. Right clic ...
- VBS 文件选择框,选择Excel文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 on error resume Next Set objDialog=CreateObject("UserAcc ...
- classpath获取--getResource()
在java中的API里,有两种方式来使用classpath读取资源. 1. Class的getResource() 2. ClassLoader的getResource() 但是两者有一定区别,运行以 ...
- JavaScript高级程序设计:第五章
引用类型 一.object类型: 创建object实例的方式有两种.第一种是使用new操作符后跟Object构造函数,如下所示: var person = new Object(): person ...