zoukankan      html  css  js  c++  java
  • Zepto源代码分析之二~三个API

    因为时间关系:本次仅仅对这三个API($.camelCase、$.contains、$.each)方法进行分析

    第一个方法变量转驼峰:$.camelCase('hello-world-welcome');
    源代码:
    var camelize;
    /**
     * 字符串替换
     * 使用replace第二个參数带回调
     */
    camelize = function(str) {
         return str.replace(/-+(.)?/g,
              function(match, chr) {
                   return chr ? chr.toUpperCase() : '';
              }
         );
    };
    /**
     * 将一组字符串变成驼峰命名法
     */
    $.camelCase = camelize;

    第二个方法检查父节点是否包括给定的dom节点,假设两者是同样节点,返回false:$.contains(parent, node)
    源代码:
    /**
     * $.contains(parent, node);
     * 检查父节点是否包括给定的dom节点,假设两者是同样节点,返回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;  
         };

    第三个方法遍历数组或以key-value值对方式遍历对象。回调函数返回false时停止遍历。
    $.each(collection, function(index, item) { ... }) => collection
    遍历数组元素或以key-value值对方式遍历对象。

    回调函数返回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 数据对象
     * @param {function} callback 回调函数
     * return {object|array} elements 数据对象
     */
    $.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;
    };

    三个方法最后页面: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>这是測试内容</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;
        };


        /**
         * 检測函数
         */
        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第二个參数带回调
         */
        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-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] : []) :
                slice.call((isSimple && !maybeID) ?
                    maybeClass ?

    element.getElementsByClassName(nameOnly) : // class名称
                    element.getElementsByTagName(selector) : // tag名称
                    element.querySelectorAll(selector) // 查询全部匹配到的
                );
        };
        /**
         * $.contains(parent, node); 演示样例$.contains($('#test')[0], $('.aa')[0])
         * 检查父节点是否包括给定的dom节点,假设两者是同样节点,返回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);
        }
        // 函数參数
        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 数据对象
         * @param {function} callback 回调函数
         * return {object|array} elements 数据对象
         */
        $.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 = {
            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 (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);


    浏览器输出结果:











  • 相关阅读:
    判断ImageIcon创建成功
    Node中的explorer views的双击事件
    Oracle数据类型
    Sql三种行转列
    数据库迁移
    并发采集同一站点被封的解决方案
    .net获取版本号的三种方法
    List转DataSet
    Orcale自增长主键
    python学习笔记数字和表达式
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6963688.html
Copyright © 2011-2022 走看看