zoukankan      html  css  js  c++  java
  • Zepto源代码分析一~核心方法

    今天抽出时间复习了一下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-zd])([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>

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





  • 相关阅读:
    Binary Tree Zigzag Level Order Traversal
    Binary Tree Level Order Traversal
    Symmetric Tree
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Triangle
    Populating Next Right Pointers in Each Node II
    Pascal's Triangle II
    Pascal's Triangle
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6724779.html
Copyright © 2011-2022 走看看