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 学习之路——第一步、基本入门
话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...
随机推荐
- UIAlertAction 弹出对话框9.0后有点变化
ios 9.0后再用以前的UIAlertAction 已经不行了 被弃用了 改用这种方法了 UIAlertController *alertController = [UIAlertControlle ...
- Hibernate中自带ID的generator的含义
increment:代理主键,适合于所有数据库,由hibernate维护主键自增,和底层数据库无关,但是不适合于2个或以上hibernate进程. identity:代理主键,适合于Mysql或ms ...
- Tenured 区并发垃圾回收器CMS介绍
当使用CMS收集器时,当开始进行收集时,old代的收集过程如下所示:1,首先jvm根据-XX:CMSInitiatingOccupancyFraction,-XX:+UseCMSInitiatingO ...
- hdu-5794 A Simple Chess(容斥+lucas+dp)
题目链接: A Simple Chess Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Ot ...
- 《C++ Primer》之面向对象编程(二)
构造函数和复制控制 每个派生类对象由派生类中定义的(非 static)成员加上一个或多个基类子对象构成,当我们构造.复制.赋值和撤销一个派生类对象时,也会构造.复制.赋值和撤销这些基类子对象. 构造函 ...
- WIN2003 设置 OPENVPN 服务端
服务器端 安装openvpn 在这里http://swupdate.openvpn.org/community/releases/openvpn-install-2.3.4-I004-i686.exe ...
- TCP/IP协议学习之实例ping命令学习笔记
TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...
- delete、truncate与drop的区别
转自:SQL truncate .delete与drop区别 相同点: 1.truncate和不带where子句的delete.以及drop都会删除表内的数据. 2.drop.truncate都是DD ...
- python datetime时间差
import datetime import time d1 = datetime.datetime(2005, 2, 16) d2 = datetime.datetime(2004, 12, 31) ...
- PHP中GD库安装
安装gd库扩展不能像其他扩展安装一样,直接./configure --prefix=/xxx 还需要激活png,jpeg,字库等支持 ./configure --prefix=/xxx --with- ...