zepto源码学习-01-整体感知

在公司一直做移动端的项目,偶尔会做点PC端的东西,但基本上都是和移动端打交道,移动端嘛必须上zepto。

简单介绍下Zepto,它是一个面向高级浏览器的JavaScript框架的,实现JQuery的大部分API,尤其针对手机上web开发(流量金贵,JQ又太重了,体积太大,考虑太多性能不好),因此选择Zepto.js一个非常不错的选择!纵观各大网站选用zepto的特别多。

做移动端为了让页面更轻巧,大多都是自己写原生代码,遇到难题,我一般都是去看zepto的实现,把其中的一些搬到自己代码中,久而久之、对zepto就熟悉了。

进入正题:zepto官网 地址

再上一张图,一个大神画的,不是我画的。

这张图基本上包含了zepto的api,并且进行了分类。

在该github上下载zepto的源码也是进行模块划分的

在官网上下载的zepto默认导入了其中五个个模块

从github上下载下来的代码可以看到有很多个文件,其中的核心文件就是zepto

先从这个文件入手,看下这个文件903行,声明了一个全局变量Zepto,照理说Zepto已经挂载到window上了,这里为什么还window.Zepto = Zepto再次进行赋值,不解!

window.$ === undefined && (window.$ = Zepto)

windwo上的$对象没有被占用就直接赋值为Zepto,我们平时使用$(XXX)的时候也可以替换成Zepto(XXX),但是没有必要,多写四个字符不累啊!

var Zepto=(function(){XXXX})();

Zepto后面是一个立即执行函数,内部肯定返回了某个对象然后赋值给Zepto

所以我展开立即执行函数,反倒最下面看到以下代码

    //把$.fn赋值给Z.prototype、zepto.Z.prototype
    zepto.Z.prototype = Z.prototype = $.fn

    // Export internal API functions in the `$.zepto` namespace
    zepto.uniq = uniq
    zepto.deserializeValue = deserializeValue
    $.zepto = zepto
    //返回内部的$对象
    return $

其他的代码先不管什么意思,反正这里返回了$对象,那么我们平时使用的全局$其实就是内部的$,最后看下内部哪里声明的$这个东西

    $ = function(selector, context) {
        return zepto.init(selector, context)
    }

发现内部的$其实就是一个函数,内部是return zepto.init(selector, context)

我们平时写的$(XXX) 其实就是调用的zepto.init(XX)

再次回到原点,平时我们都是怎么使用$ 都有哪些用法,JQuery的$好像有八九用法

1. jQuery([selector,[context]])
2. jQuery(element)
3. jQuery(elementArray)
4. jQuery(object)
5. jQuery(jQuery object)
6. jQuery(html,[ownerDocument])
7. jQuery(html,[attributes])
8. jQuery()
9. jQuery(callback)

zepto总结下也就三种

1、$(selector,context?) 传入一个选择器返回一个zepto对象

2、$(function(){}) 传入一个函数,dom ready时执行

3、$(html,attrs?) 传入一个html字符串,构建元素,返回一个或zepto对象

4、$(dom obj)传入dom对象返回zepto对象

以上操作最后都是调用zepto.init(selector, context),我们的重点就是分析zepto.init这个函数

    zepto.init = function(selector, context) {
        var dom
            // If nothing given, return an empty Zepto collection
            // 如果啥都没传直接返回一个空的Zepto集合
        if (!selector) return zepto.Z()
            // Optimize for string selectors
            // 如果第一个参数是string
        else if (typeof selector == ‘string‘) {
            //去掉空格
            selector = selector.trim()
                // If it‘s a html fragment, create nodes from it
                // Note: In both Chrome 21 and Firefox 15, DOM error 12
                // is thrown if the fragment doesn‘t begin with <
                //  如果是一个HTML片段,创建节点注意,在chrome21和FF15版本,
                         // DOM错误12不是以<被抛出
            if (selector[0] == ‘<‘ && fragmentRE.test(selector))
                dom = zepto.fragment(selector, RegExp.$1, context), selector = null
                // If there‘s a context, create a collection on that context first, and select
                // nodes from there
                //如果存在一个上下文环境,在这个上下文对象中去选择节点
            else if (context !== undefined) return $(context).find(selector)
                // If it‘s a CSS selector, use it to select nodes.
            // 如果是一个css选择器,用它来选择节点
            else dom = zepto.qsa(document, selector)
        }
        // If a function is given, call it when the DOM is ready
         // 如果一个函数存在,在domready就绪后触发
        else if (isFunction(selector)) return $(document).ready(selector)
            // If a Zepto collection is given, just return it
            // 如果zepto已经收集给出,直接返回
        else if (zepto.isZ(selector)) return selector
        else {
            // normalize array if an array of nodes is given
            // 如果节点已经为数组,进行聚合
            if (isArray(selector)) dom = compact(selector)
                // Wrap DOM nodes.
            // 包装DOM节点
            else if (isObject(selector))
                dom = [selector], selector = null
                // If it‘s a html fragment, create nodes from it
            // 如果是一个HTML片段,对该片段创建节点
            else if (fragmentRE.test(selector))
                dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
                // If there‘s a context, create a collection on that context first, and select
                // nodes from there
            else if (context !== undefined) return $(context).find(selector)
                // And last but no least, if it‘s a CSS selector, use it to select nodes.
            else dom = zepto.qsa(document, selector)
        }
        // create a new Zepto collection from the nodes found
         // 对发现的节点创建一个新的Zepto集合,这里把查询到dom 对象和selector 传递给了zepto.Z
        return zepto.Z(dom, selector)
    }

最后返回的是zepto.Z(dom, selector),最终我们还得看zepto.Z的实现

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

其实相当于一个工厂方法,在这里new了一个Z,外面每次我们调用$ 最后拿到的都是新的实例对象,但是我们并没有new,其实就是这里帮我们new了,JQuery也这样,这种思想到处都有用到。

最后我们还得参看Z的实现

    function Z(dom, selector) {
        var i, len = dom ? dom.length : 0
        //把dom对象数组放到this上,所以我们外部可以XX[0]得到一个原生的dom对象,关键就在这里,this是一个伪数组
        for (i = 0; i < len; i++) this[i] = dom[i]
        //把长度赋给this.length
        this.length = len
        //这个就不说了
        this.selector = selector || ‘‘
    }

直接返回了一个Z的实例对象。先看一个demo

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test zepto</title>
    <meta  name="viewport" content="width=device-width,initial-scale=1.0,minimum-cacle=1.0,maximum-scale=1.0">
    <meta content="telephone=no" name="format-detection">
    <meta content="email=no"  name="format-detection">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <style> </style>
</head>
<body>
    <h1 id=‘test‘>test</h1>
    <ul id=‘items‘>
        <li>List item 1 <span class=‘delete‘>DELETE</span></li>
        <li>List item 2 <span class=‘delete‘>DELETE</span></li>
    </ul>
    <div id=‘block‘></div>
    <script type="text/javascript" src="../zepto-full-1.1.6.js"></script>
    <script>
    var s=$(‘#items‘);
    console.log(s)
    </script>
</body>
</html>

这个demo 我们得到的test1对象如下

按之前的分析Z对象有length ;;Z[0]、Z[1]…… 伪数组;还有selector

但是现在Z的原型指向了zepto.z[0];所以返回的对象我们可以test1.attr()、test1.addClass()、test1.after()我们可以访问这些方法,是因为这个实力对象的原型能够访问到这些方法。那么问题来了,Z的原型什么时候指向zepto.z[0]

带着这个疑问,继续查看源码,发下如下代码

    //把$.fn赋值给Z.prototype、zepto.Z.prototype
    zepto.Z.prototype = Z.prototype = $.fn
    // Export internal API functions in the `$.zepto` namespace
    zepto.uniq = uniq
    zepto.deserializeValue = deserializeValue
    $.zepto = zepto
    //返回内部的$对象
    return $
$.fn下的所有方法都挂在了zepto.Z的prototype和Z.prototype下,也就是说上面的test1已经拥有了$.fn的所有方法。$.fn上的方法也就是$的实例方法,$上还有一大堆静态方法,不用创建一个$对象也可以调用。我使用的版本是1.1.6,以前的版本 在这里实现略有不同,但是大同小异,搞懂了原型、原型链、继承这些都不是问题。

细心的话会发现一个问题,test的__proto__ 指向的是zepto.z[0], 试问问为什么会是zepto.z[0]这个东西,感觉怪怪的。为什么会是zepto.z[0]、zepto.z[0]是什么东西,下回分解!!
时间: 2024-11-07 20:45:41

zepto源码学习-01-整体感知的相关文章

【iScroll源码学习01】准备阶段 - 叶小钗

[iScroll源码学习01]准备阶段 - 叶小钗 时间 2013-12-29 18:41:00 博客园-原创精华区 原文  http://www.cnblogs.com/yexiaochai/p/3496369.html 主题 iScroll HTML JavaScript ① viewport相关知识点(device-width等) ②  CSS3硬件加速 ③ 如何暂停CSS动画 ④ e.preventDefault导致文本不能获取焦点解决方案 ...... 当然,我们写的demo自然不能和

jQuery 源码学习 - 01 - 简洁的 $(&#39;...&#39;)

首先贴上学习参考资料:[深入浅出jQuery]源码浅析--整体架构,备用地址:chokcoco/jQuery-. jQuery 库,js 开发的一个里程碑,它的出现,让网页开发者们告别荒蛮的上古时代,初步解放生产力,正式进入黄铜时代. 虽然如今 Angular/React/Vue 三驾马车驰骋畋猎,jQuery的时代渐行渐远,但是它的思想它的设计都有着里程碑式的作用.当然,我是拿它来补基础的,逃... 1.自执行函数 (function(params) { // ... })(Variable)

zepto源码学习-05 ajax

学习zeptoajax之前需要先脑补下,强烈推荐此文http://www.cnblogs.com/heyuquan/archive/2013/05/13/js-jquery-ajax.html 还有Aaron 的jquery源码分析系列,讲jquery的ajax的部分,当然其他也可以看,很值得学习. zepto ajax部分的设计相对简单,毕竟zepto就是轻量级的库,没有jqeury那样复杂,jquery ajax是依赖于Deferred模块的,整个代码一千多行.而zepto只有几百行,整体设

jQuery源码学习1——整体架构篇

由于jQuery的源码比较复杂,所以我选择从jQuery1.0.0版本开始学习,逐步深入. 而且本系列文章包含大量的个人观点,纯属本人学习的记录 jQuery1.0.0只有1800行左右的代码,相对来讲看起来还是比较简单的 首先,想说一下我对jQuery的理解 jQuery其实就是一个很大的构造函数 它为我们提供了很多实例化方法 当然,由于在js中函数本身就是对象 因此jQuery也提供了很多的静态方法 个人认为,这些静态方法更为底层 今天把jQuery的架构梳理了一下 其实我们可以将其中的方法

zepto源码学习-03 $()

在第一篇的时候提到过关于$()的用法,一个接口有很多重载,用法有很多种,总结了下,大概有一以下几种 1.$(selector,context?) 传入一个选择器返回一个zepto对象 2.$(function(){}) 传入一个函数,dom ready时执行 3.$(html,attrs?) 传入一个html字符串,构建元素,返回一个或zepto对象 4.$(dom obj)传入dom对象返回zepto对象 $()最终调用的zepto.init方法,对以上四种情况做相应处理,该方法有6个retu

Nmap 源码学习二 整体架构

目录功能: docs :相关文档 libdnet-stripped :开源网络接口库 liblinear:开源大型线性分类库 liblua:开源Lua脚本语言库 libnetutil:基本的网络函数 libpcap:开源抓包库 libpcre:开源正则表达式库 macosx:xcode项目文件 mswin32:vs项目文件 nbase:Nmap封装的基础使用函数库 ncat:netcat网络工具,由Nmap实现 ndiff:比较Nmap扫描结果的实用命令 nmap-update:负责Nmap更新

zepto源码学习-06 touch

先上菜,看这个模块的最后一段代码,一看就明白. ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap' ].forEach(function(eventName) { $.fn[eventName] = function(callback) { return this.on(eventName, callback) } }) tap —元素tap

zepto源码学习-04 event

之前说完$(XXX),然后还有很多零零碎碎的东西需要去分析,结果一看代码,发现zepto的实现都相对简单,没有太多可分析的.直接略过了一些实现,直接研究Event模块,相比JQuery的事件系统,zepto的设计相对简单很多,看起来也就相对轻松,整个event模块也就300行代码. 先看事件的相关接口以及用法 $.Event $.Event(type, [properties]) ⇒ event 创建并初始化一个指定的DOM事件.如果给定properties对象,使用它来扩展出新的事件对象.默认

【iScroll源码学习02】分解iScroll三个核心事件点

前言 最近两天看到很多的总结性发言,我想想今年好像我的变化挺大的,是不是该晚上来水一发呢?嗯,决定了,晚上来水一发! 上周六,我们简单模拟了下iScroll的实现,周日我们开始了学习iScroll的源码,今天我们接着上次的记录学习,因为最近事情稍微有点多了 学习进度可能要放慢,而且iScroll这个库实际意义很大,不能囫囵吞枣的学习,要学到精华,并且要用于项目中的,所以初步规划是最近两周主要围绕iScroll展开 而后两个选择:① 分离iScroll代码用于项目:② 抄袭iScroll精华部分用