Zepto源代码分析之二~三个API
第一個方法變量轉(zhuǎn)駝峰:$.camelCase('hello-world-welcome'); 源代碼: var camelize; /** * 字符串替換 * 使用replace第二個參數(shù)帶回調(diào) */ camelize = function(str) { return str.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : ''; } );
}; /** * 將一組字符串變成駝峰命名法 */ $.camelCase = camelize;
第二個方法檢查父節(jié)點是否包括給定的dom節(jié)點,假設(shè)兩者是同樣節(jié)點,返回false:$.contains(parent, node) 源代碼: /**
?* $.contains(parent, node);
?* 檢查父節(jié)點是否包括給定的dom節(jié)點,假設(shè)兩者是同樣節(jié)點,返回false
?* return {boolean} true/false
?*/ $.contains = document.documentElement.contains ? function (parent, node) { return parent !== node && parent.contains(node); } : function (parent, node) { while (node && (node = node.parentNode)) { if (node === parent) { return true; } } return false; ? };
第三個方法遍歷數(shù)組或以key-value值對方式遍歷對象。回調(diào)函數(shù)返回false時停止遍歷。 $.each(collection, function(index, item) { ... }) => collection 遍歷數(shù)組元素或以key-value值對方式遍歷對象。
回調(diào)函數(shù)返回false時停止遍歷。
$.each(['a', 'b', 'c'], function(index, item) { console.log('item %d is: %s', index, item); }); var hash = { name: 'zepto.js', size: 'micro' }; $.each(hash, function(key, value) { console.log('%s: %s', key, value); });源代碼: /** * Zepto對象迭代器 * @param {object|array} elements 數(shù)據(jù)對象 * @param {function} callback 回調(diào)函數(shù) * return {object|array} elements 數(shù)據(jù)對象 */ $.each = function(elements, callback) { var i; var key; // 數(shù)組檢測 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; };
三個方法最后頁面:demo.html <!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="bb">2332</span>
??????? </div>
??????? <div class="wrap">content</div>
??????? <script src="zepto-dev.js"></script>
??????? <script>
??????????? console.log($('div'));
??????????? console.log($('.aa'));
??????????? console.log($('<div>這是測試內(nèi)容</div>'));
??????????? console.log($("<span />", { text: "測試測試111", id: "ceshi_111", css: { color: 'red' } }));
??????????? Zepto(function($) {
??????????????? console.log('Ready to Zepto!');
??????????? });
??????? </script>
??????? <script>
??????????? console.log($.camelCase('hello-there-body'));
??????????? console.log($.contains($('#test')[0], $('.aa')[0]));
??????????? $.each(['a', 'b', 'c'], function(index, item) {
??????????????? console.log('item %d is: %s', index, item);
??????????? });
??????????? var hash = { name: 'zepto-dev.js', size: 'micro' };
??????????? $.each(hash, function(key, value) {
??????????????? console.log('%s: %s', key, value);
??????????? });
??????? </script>
??? </body>
</html>
zepto-dev.js源代碼: 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 camelize;
? ? var isArray = Array.isArray || function(object) {
? ? ? ? return object instanceof Array;
? ? };
? ? /**
? ? ?* 檢測函數(shù)
? ? ?*/
? ? 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';
? ? }
? ? /**
? ? ?* 字符串替換
? ? ?* 使用replace第二個參數(shù)帶回調(diào)
? ? ?*/
? ? function camelize(str) {
? ? ? ? return str.replace(/-+(.)?/g,
? ? ? ? ? ? function(match, chr) {
? ? ? ? ? ? ? ? console.log(chr);
? ? ? ? ? ? ? ? return chr ? chr.toUpperCase() : '';
? ? ? ? ? ? }
? ? ? ? );
? ? }
? ? 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字符串和一個可選標(biāo)記名來生成dom
? ? ?* 產(chǎn)生的dom返回一個數(shù)組形式
? ? ?* 該功能能夠被插件覆蓋
? ? ?* 沒有覆蓋全部瀏覽器
? ? ?*/
? ? zepto.fragment = function(html, name, properties) {
? ? ? ? var dom;
? ? ? ? var nodes;
? ? ? ? var container;
? ? ? ? // 標(biāo)簽特殊化處理
? ? ? ? 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`節(jié)點數(shù)組的原型賦上`$.fn`提供的全部Zepto函數(shù)
? ? ?* 請注意。`__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) {
? ? ? ? // 假設(shè)沒有給出,返回一個空的Zepto集合
? ? ? ? if (!selector) {
? ? ? ? ? ? return zepto.Z();
? ? ? ? }
? ? ? ? // 檢測字符串類型
? ? ? ? else if (typeof selector == 'string') {
? ? ? ? ? ? selector = selector.trim();
? ? ? ? ? ? /**
? ? ? ? ? ? ?* 假設(shè)是一個HTML片段,創(chuàng)建節(jié)點注意,在chrome21和FF15版本號。
? ? ? ? ? ? ?* DOM錯誤12不是以<被拋出
? ? ? ? ? ? ?*/
? ? ? ? ? ? if (selector[0] == '<' && fragmentRE.test(selector)) {
? ? ? ? ? ? ? ? dom = zepto.fragment(selector, RegExp.$1, context);
? ? ? ? ? ? ? ? selector = null;
? ? ? ? ? ? // 假設(shè)存在一個上下文環(huán)境,建立收集。并從中選擇節(jié)點
? ? ? ? ? ? } else if (context !== undefined) {
? ? ? ? ? ? ? ? return $(context).find(selector);
? ? ? ? ? ? // 假設(shè)是一個css選擇器。用它來選擇節(jié)點
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? dom = zepto.qsa(document, selector);
? ? ? ? ? ? }
? ? ? ? // 假設(shè)一個函數(shù)存在,在domready就緒后觸發(fā)
? ? ? ? } else if (isFunction(selector)) {
? ? ? ? ? ? return $(document).ready(selector);
? ? ? ? }
? ? ? ? // 假設(shè)zepto已經(jīng)收集給出,直接返回
? ? ? ? else if (zepto.isZ(selector)) {
? ? ? ? ? ? return selector;
? ? ? ? } else {
? ? ? ? ? ? // 假設(shè)節(jié)點已經(jīng)為數(shù)組,進(jìn)行聚合
? ? ? ? ? ? if (isArray(selector)) {
? ? ? ? ? ? ? ? dom = compact(selector);
? ? ? ? ? ? }
? ? ? ? ? ? // 包裝DOM節(jié)點
? ? ? ? ? ? else if (isObject(selector)) {
? ? ? ? ? ? ? ? dom = [selector];
? ? ? ? ? ? ? ? selector = null;
? ? ? ? ? ? }
? ? ? ? ? ? // 假設(shè)是一個HTML片段,對該片段創(chuàng)建節(jié)點
? ? ? ? ? ? else if (fragmentRE.test(selector)) {
? ? ? ? ? ? ? ? dom = zepto.fragment(selector.trim(), RegExp.$1, context);
? ? ? ? ? ? ? ? selector = null;
? ? ? ? ? ? }
? ? ? ? ? ? // 假設(shè)存在上下文環(huán)境,先建立收集。并從中選擇節(jié)點
? ? ? ? ? ? else if (context !== undefined) {
? ? ? ? ? ? ? ? return $(context).find(selector);
? ? ? ? ? ? }
? ? ? ? ? ? // 假設(shè)是一個css選擇器。用它來選擇節(jié)點
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? dom = zepto.qsa(document, selector);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 對發(fā)現(xiàn)的節(jié)點創(chuàng)建一個新的Zepto集合
? ? ? ? return zepto.Z(dom, selector);
? ? };
? ? // `$`作為Zepto的元對象。當(dāng)調(diào)用`$`該函數(shù)將轉(zhuǎn)由`$.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] == '.';
? ? ? ? // 確認(rèn)下標(biāo)從1開始后的字符串
? ? ? ? var nameOnly = maybeID || maybeClass ?
selector.slice(1) : selector;
? ? ? ? var isSimple = simpleSelectorRE.test(nameOnly);
? ? ? ? return (isDocument(element) && isSimple && maybeID) ?
? ? ? ? ? ? ((found = element.getElementById(nameOnly)) ? [found] : []) :
? ? ? ? ? ? slice.call((isSimple && !maybeID) ?
? ? ? ? ? ? ? ? maybeClass ?
element.getElementsByClassName(nameOnly) : // class名稱
? ? ? ? ? ? ? ? element.getElementsByTagName(selector) : // tag名稱
? ? ? ? ? ? ? ? element.querySelectorAll(selector) // 查詢?nèi)科ヅ涞降?br /> ? ? ? ? ? ? );
? ? };
? ? /**
? ? ?* $.contains(parent, node); 演示樣例$.contains($('#test')[0], $('.aa')[0])
? ? ?* 檢查父節(jié)點是否包括給定的dom節(jié)點,假設(shè)兩者是同樣節(jié)點,返回false
? ? ?* return {boolean} true/false
? ? ?*/
? ? $.contains = document.documentElement.contains ?
? ? ? ? function (parent, node) {
? ? ? ? ? ? return parent !== node && parent.contains(node);
? ? ? ? } :
? ? ? ? function (parent, node) {
? ? ? ? ? ? while (node && (node = node.parentNode)) {
? ? ? ? ? ? ? ? if (node === parent) {
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return false;
? ? ? ? };
? ? function setAttribute(node, name, value) {
? ? ? ? value == null ? node.removeAttribute(name) : node.setAttribute(name, value);
? ? }
? ? // 函數(shù)參數(shù)
? ? 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;
? ? $.camelCase = camelize;
? ? /**
? ? ?* Zepto對象迭代器
? ? ?* @param {object|array} elements 數(shù)據(jù)對象
? ? ?* @param {function} callback 回調(diào)函數(shù)
? ? ?* return {object|array} elements 數(shù)據(jù)對象
? ? ?*/
? ? $.each = function(elements, callback) {
? ? ? ? var i;
? ? ? ? var key;
? ? ? ? // 數(shù)組檢測
? ? ? ? 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 = {
? ? ? ? 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屬性設(shè)置
? ? ? ? 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 (var 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 = zepto;
? ? return $;
})();
// 全局變量接口
window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);
瀏覽器輸出結(jié)果:
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的Zepto源代码分析之二~三个API的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 99% 的新移动恶意程序是针对 Andr
- 下一篇: 面对 20 亿行代码,Google 如何