今天抽出时间复习了一下Zepto的源代码,依照自己的理解进行凝视。

欢迎大家拍砖。

源代码版本号:v1.1.4

源代码下载地址:http://zeptojs.com/

分析总体代码之后,整理出架构图:


本次仅仅针对获取核心方法$()进行拨离,并用demo測试api。
var Zepto = (function() {
// 变量初始化
var $;
var zepto = {};
var fragmentRE = /^\s*<(\w+|!)[^>]*>/;
var singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
var tagExpanderRE = /<(? !area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig;
var undefined;
var emptyArray = [];
var slice = emptyArray.slice;
var cssNumber = {
'column-count': 1,
'columns': 1,
'font-weight': 1,
'line-height': 1,
'opacity': 1,
'z-index': 1,
'zoom': 1
};
// 特殊属性集合
var methodAttributes = [ 'val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset' ];
var table = document.createElement('table');
var tableRow = document.createElement('tr');
var containers = {
'tr': document.createElement('tbody'),
'tbody': table,
'thead': table,
'tfoot': table,
'td': tableRow,
'th': tableRow,
'*': document.createElement('div')
};
var readyRE = /complete|loaded|interactive/;
var simpleSelectorRE = /^[\w-]*$/;
var class2type = {};
var toString = class2type.toString;
var isArray = Array.isArray || function(object) {
return object instanceof Array;
};
function type(obj) {
return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
}
function isFunction(value) {
return type(value) == "function";
}
function isWindow(obj) {
return obj != null && obj == obj.window;
}
function isDocument(obj) {
return obj != null && obj.nodeType == obj.DOCUMENT_NODE;
}
function isObject(obj) {
return type(obj) == "object";
}
function isPlainObject(obj) {
return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype;
}
function likeArray(obj) {
return typeof obj.length == 'number';
}
function dasherize(str) {
return str.replace(/::/g, '/')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
.replace(/_/g, '-')
.toLowerCase()
}
function maybeAddPx(name, value) {
return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value;
}
/**
* `$.zepto.fragment`须要一个html字符串和一个可选标记名来生成dom
* 产生的dom返回一个数组形式
* 该功能能够被插件覆盖
* 没有覆盖全部浏览器
*/
zepto.fragment = function(html, name, properties) {
var dom;
var nodes;
var container;
// 标签特殊化处理
if (singleTagRE.test(html)) {
dom = $(document.createElement(RegExp.$1));
}
if (!dom) {
if (html.replace) {
html = html.replace(tagExpanderRE, "<$1></$2>");
}
if (name === undefined) {
name = fragmentRE.test(html) && RegExp.$1;
}
if (!(name in containers)) {
name = '*';
}
container = containers[name];
container.innerHTML = '' + html;
dom = $.each(slice.call(container.childNodes), function() {
container.removeChild(this);
});
}
if (isPlainObject(properties)) {
nodes = $(dom);
$.each(properties, function(key, value) {
if (methodAttributes.indexOf(key) > -1) {
nodes[key](value);
} else {
nodes.attr(key, value);
}
});
}
return dom;
};
/**
* `$.zepto.Z`将给定`dom`节点数组的原型赋上`$.fn`提供的全部Zepto函数
* 请注意,`__proto__`不支持IE浏览器
*/
zepto.Z = function(dom, selector) {
dom = dom || [];
dom.__proto__ = $.fn;
dom.selector = selector || '';
return dom;
};
// `$.zepto.isZ`检查给定的对象是一个Zepto的集合,可被插件覆盖
zepto.isZ = function(object) {
return object instanceof zepto.Z;
};
/**
* `$.zepto.init`是Zepto借鉴jQuery的`$.fn.init`
* 採用css选择器和一个可选的上下文(处理各种特殊情况)
* 该方法可被插件覆盖
*/
zepto.init = function(selector, context) {
// 假设没有给出,返回一个空的Zepto集合
if (!selector) {
return zepto.Z();
// 检測字符串类型
} else if (typeof selector == 'string') {
selector = selector.trim();
/**
* 假设是一个HTML片段,创建节点注意,在chrome21和FF15版本号,
* DOM错误12不是以<被抛出
*/
if (selector[0] == '<' && fragmentRE.test(selector)) {
dom = zepto.fragment(selector, RegExp.$1, context);
selector = null;
}
// 假设存在一个上下文环境。建立收集,并从中选择节点
else if (context !== undefined) {
return $(context).find(selector);
}
// 假设是一个css选择器,用它来选择节点
else {
dom = zepto.qsa(document, selector);
}
}
// 假设一个函数存在,在domready就绪后触发
else if (isFunction(selector)) {
return $(document).ready(selector);
}
// 假设zepto已经收集给出,直接返回
else if (zepto.isZ(selector)) {
return selector;
}
else {
// 假设节点已经为数组。进行聚合
if (isArray(selector)) {
dom = compact(selector);
}
// 包装DOM节点
else if (isObject(selector)) {
dom = [selector];
selector = null;
}
// 假设是一个HTML片段。对该片段创建节点
else if (fragmentRE.test(selector)) {
dom = zepto.fragment(selector.trim(), RegExp.$1, context);
selector = null;
}
// 假设存在上下文环境,先建立收集,并从中选择节点
else if (context !== undefined) {
return $(context).find(selector);
}
// 假设是一个css选择器。用它来选择节点
else {
dom = zepto.qsa(document, selector);
}
}
// 对发现的节点创建一个新的Zepto集合
return zepto.Z(dom, selector);
};
// `$`作为Zepto的元对象。当调用`$`该函数将转由`$.zepto.init`处理
$ = function(selector, context) {
return zepto.init(selector, context);
};
/**
* `$.zepto.qsa`是Zepto的css选择器。使用document.querySelectorAll及特殊情况处理
* 可被插件覆盖
*/
zepto.qsa = function(element, selector) {
var found;
var maybeID = (selector[0] == '#');
var maybeClass = !maybeID && selector[0] == '.';
// 确认下标从1開始后的字符名
var nameOnly = maybeID || maybeClass ? selector.slice(1) : selector;
var isSimple = simpleSelectorRE.test(nameOnly);
return (isDocument(element) && isSimple && maybeID) ?
((found = element.getElementById(nameOnly)) ? [found] : []) :
(element.nodeType !== 1 && element.nodeType !== 9) ? [] :
slice.call((isSimple && !maybeID) ?
maybeClass ? element.getElementsByClassName(nameOnly) : //class名称
element.getElementsByTagName(selector) : // tag名称
element.querySelectorAll(selector) // 查询全部匹配到的
);
};
function setAttribute(node, name, value) {
value == null ? node.removeAttribute(name) : node.setAttribute(name, value);
}
// 函数參数
function funcArg(context, arg, idx, payload) {
return isFunction(arg) ? arg.call(context, idx, payload) : arg;
}
$.type = type;
$.isFunction = isFunction;
$.isWindow = isWindow;
$.isArray = isArray;
$.isPlainObject = isPlainObject;
// Zepto对象迭代器
$.each = function(elements, callback) {
var i;
var key;
if (likeArray(elements)) {
for (i = 0; i < elements.length; i++) {
if (callback.call(elements[i], i, elements[i]) === false) {
return elements;
}
}
} else {
for (key in elements) {
if (callback.call(elements[key], key, elements[key]) === false) {
return elements;
}
}
}
return elements;
};
// 配置类型映射
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
/**
* 定义的方法。适用于全部的Zepto对象
*/
$.fn = {
slice: function() {
return $(slice.apply(this, arguments));
},
ready: function(callback) {
// 检查document.body存在且文档渲染完毕
if (readyRE.test(document.readyState) && document.body) {
callback($);
} else {
document.addEventListener('DOMContentLoaded', function() {
callback($);
}, false);
}
},
each: function(callback) {
emptyArray.every.call(this, function(el, idx) {
return callback.call(el, idx, el) !== false;
});
return this;
},
text: function(text) {
return 0 in arguments ?
this.each(function(idx) {
var newText = funcArg(this, text, idx, this.textContent);
this.textContent = (newText == null) ? '' : '' + newText;
}) :
(0 in this ? this[0].textContent : null);
},
attr: function(name, value) {
var result;
return (typeof name == 'string' && !(1 in arguments)) ? (!this.length || this[0].nodeType !== 1 ? undefined :
(!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
) :
this.each(function(idx) {
if (this.nodeType !== 1) {
return;
}
if (isObject(name)) {
for (key in name) {
setAttribute(this, key, name[key]);
}
} else {
setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)));
}
});
},
// css属性设置
css: function(property, value) {
if (arguments.length < 2) {
var element = this[0];
var computedStyle = getComputedStyle(element, '');
if (!element) {
return;
}
if (typeof property == 'string') {
return element.style[camelize(property)] || computedStyle.getPropertyValue(property);
} else if (isArray(property)) {
var props = {};
$.each(isArray(property) ? property : [property], function(_, prop) {
props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop));
});
return props;
}
}
var css = '';
if (type(property) == 'string') {
if (!value && value !== 0) {
this.each(function() {
this.style.removeProperty(dasherize(property));
});
} else {
css = dasherize(property) + ":" + maybeAddPx(property, value);
}
} else {
for (key in property) {
if (!property[key] && property[key] !== 0) {
this.each(function() {
this.style.removeProperty(dasherize(key));
});
} else {
css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';';
}
}
}
return this.each(function() {
this.style.cssText += ';' + css;
});
}
};
// 继承
zepto.Z.prototype = $.fn;
// 在`$.zepto`命名空间导出内部API函数
zepto.uniq = uniq;
zepto.deserializeValue = deserializeValue;
$.zepto = zepto;
return $;
})();
// 全局变量接口
window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);
演示样例流程:
当我们运行一个$("#test"),详细过程例如以下:

1. 运行zepto.init
2. 获取这个元素,最后返回一个数组,然后运行 zepto.Z(dom, selector)
3. 将数组化后的节点列表的__proto__运行zepto.Z.prototype。注意到zepto.Z.prototype = $.fn,$.fn下的全部方法都挂在了zepto.Z的prototype下,也就是说$("#test")已经拥有了$.fn的全部方法
4. 返回数组

相应的demo页面代码:
<!DOCTYPE html>

<html>

    <head>

        <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

        <meta charset="utf-8" />

        <title>Zepto源代码分析</title>

        <link rel="stylesheet" href="demo.css" type="text/css" />

    </head>

    <body>

        <div id="test">

            測试zepto源代码

            <span class="aa">22</span>

            <span class="aa">2332</span>

        </div>

        <div class="wrap">content</div>

        <script src="zepto-dev.js"></script>

        <script>

            console.log($('div'));

            console.log($('.aa'));

            console.log($('<div>这是測试内容</div>'));

            console.log($("<span />", { text: "測试測试111", id: "ceshi_111", css: { color: 'red' } }));

            Zepto(function($) {

                console.log('Ready to Zepto!');

            });

        </script>

    </body>

</html>

最后的效果截图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenFqZmxhc2g=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="784" alt="" style="">





Zepto源代码分析一~核心方法的更多相关文章

  1. Zepto源代码分析之二~三个API

    因为时间关系:本次仅仅对这三个API($.camelCase.$.contains.$.each)方法进行分析 第一个方法变量转驼峰:$.camelCase('hello-world-welcome' ...

  2. Spark SQL源代码分析之核心流程

    /** Spark SQL源代码分析系列文章*/ 自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几 ...

  3. zepto源码--核心方法(类数组相关)--学习笔记

    从这篇起,在没有介绍到各类插件之前,后面将陆续介绍zepto对外暴露的核心方法.即$.fn={}里面的所有方法的介绍.会配合zepto的API进行介绍. 其实前面已经介绍了几个,如width,heig ...

  4. Spark SQL Catalyst源代码分析之UDF

    /** Spark SQL源代码分析系列文章*/ 在SQL的世界里,除了官方提供的经常使用的处理函数之外.一般都会提供可扩展的对外自己定义函数接口,这已经成为一种事实的标准. 在前面Spark SQL ...

  5. Spark SQL 源代码分析系列

    从决定写Spark SQL文章的源代码分析,到现在一个月的时间,一个又一个几乎相同的结束很快,在这里也做了一个综合指数,方便阅读,下面是读取顺序 :) 第一章 Spark SQL源代码分析之核心流程 ...

  6. SpringMVC源代码深度分析DispatcherServlet核心的控制器(初始化)

    SpringMVC是非常优秀的MVC框架,每一个框架都是为了我们提高开发效率,我们试图通过对SpringMVC的源码去了解这个框架,了解整个设计思想,框架要有扩展性,这里用的比較多是接口和抽象,是框架 ...

  7. XBMC源代码分析 3:核心部分(core)-综述

    前文分析了XBMC的整体结构以及皮肤部分: XBMC源代码分析 1:整体结构以及编译方法 XBMC源代码分析 2:Addons(皮肤Skin) 本文以及以后的文章主要分析XBMC的VC工程中的源代码. ...

  8. Linux内核源代码分析方法

    Linux内核源代码分析方法   一.内核源代码之我见 Linux内核代码的庞大令不少人"望而生畏",也正由于如此,使得人们对Linux的了解仅处于泛泛的层次.假设想透析Linux ...

  9. 【zepto学习笔记01】核心方法$()

    前言 我们移动端基本使用zepto了,而我也从一个小白变成稍微靠谱一点的前端了,最近居然经常要改到zepto源码但是,我对zepto不太熟悉,其实前端水准还是不够,所以便私下偷偷学习下吧,别被发现了 ...

随机推荐

  1. php获取开始与结束日期之间所有日期的方法

    /** * 获取指定日期段内每一天的日期 * @param Date $startdate 开始日期 * @param Date $enddate 结束日期 * @return Array */ fu ...

  2. /etc/fstab格式的问题

    [root@localhost etc]# cat fstab /dev/VolGroup00/LogVol00 /                       ext3    defaults    ...

  3. Unity接入谷歌支付

    文章理由 前段时间负责Unity接入Google内购功能,一开始研究别人的技术博客时发现,他们的文章都有些年头了,有些细节的地方已经不像n年前那样了,技术永远是需要更新的,而这篇就作为2016年末的最 ...

  4. 第八章openwrt 703N使用HUB(集线器)插U盘等设备

    在这里就要吐槽一下了,在网上一搜索竟然没有一篇详细的关于703N使用hub后挂载u盘的文章,想了很久问了别人还弄了一天晚上终于弄好了.好吧下面开始言归正传: 1.其实一般质量可以的集线器例如SSK这类 ...

  5. CSS:CSS层叠样式表的概述

    CSS层叠样式表:Cascading Style Sheets 介绍: 现代网页的设计原则是内容和样式分离,降低它们之间的直接相互依存关系,解耦性,同时,同样的内容,可以通过不同的CSS样式表现出来. ...

  6. iOS:删除storyBoard,纯代码实现UITabBarController的视图切换功能

    storyboard是一个很强大的编写代码的辅助工具,可以帮助布局多个视图之间的联系,既直观又能减少代码量:但是,作为一个程序员,在不使用storyboard的情况下,纯代码编写是必须的技能. 下面就 ...

  7. QT在windows下的安装与配置

    先了解Qt: Qt一直以来,分为商业.开源两个版本,商业版本为用户提供了二级制的动态库,直接安装既可以使用,但是需要花钱购买license,而开源版本则遵守GPL协议,提供了源码,用户需要自行编译,才 ...

  8. go语言基础之基匿名函数本语法和闭包

    一.匿名函数 示例1: package main import "fmt" func main() { a := 10 str := "mike" //匿名函数 ...

  9. TensorFlowIO操作(二)----读取数据

    读取数据 小数量数据读取 这仅用于可以完全加载到存储器中的小的数据集有两种方法: 存储在常数中. 存储在变量中,初始化后,永远不要改变它的值. 使用常数更简单一些,但是会使用更多的内存,因为常数会内联 ...

  10. C#中 父类与子类相互强制转换之实验

    MSDN是很好,不过,有时需要自己动手实践一下,才能更好的理解和记住一些东西. 我看过很多技术文章,结果到用时,仍然是下不了手.似是而非的. 像上次写的“四舍六入五成双/四舍六入五留双/四舍六入五单双 ...