在zepto中,通过$来构造对象
$ = function(selector, context){ return zepto.init(selector, context) }
由该函数,实际上,在调用$函数时相当于调用init方法,接下来看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 else if (typeof selector == ‘string‘) { //消除空格 selector = selector.trim() //这里根据不同的情况返回dom 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. else dom = zepto.qsa(document, selector) } // If a function is given, call it when the DOM is ready else if (isFunction(selector)) return $(document).ready(selector) // If a Zepto collection is given, just return it 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. else if (isObject(selector)) dom = [selector], selector = null // If it‘s a html fragment, create nodes from it 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 return zepto.Z(dom, selector) };
先来看一下当传入的是一个html标签的字符串时的构造过程:
if (selector[0] == ‘<‘ && fragmentRE.test(selector)) dom = zepto.fragment(selector, RegExp.$1, context), selector = null fragmentRE = /^\s*<(\w+|!)[^>]*>/;
fragmentRE是一个匹配普通标签<xxx>的表达式,关键是zepto.fragment()函数。
该函数传入三个参数,在这里传入的分别是selector, RegExp.$1, context,RegExp.$1储存的是当前调用的正则表达式匹配的第一个子表达式。即当我们传入<span>时,其值为span,接下来可以看fragment函数。
zepto.fragment = function(html, name, properties) { var dom, nodes, container // A special case optimization for a single tag //创建一个元素 if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) if (!dom) { //将html转换为标签,$1$2表示的是匹配的第一个和第二个子表达式 if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 //创建一个name元素 根据是否为表格元素对其进行下一步操作 if (!(name in containers)) name = ‘*‘ container = containers[name] //将标签插入name元素 container.innerHTML = ‘‘ + html //$.each函数最终返回传入的第一个数组参数 dom = $.each(slice.call(container.childNodes), function(){ container.removeChild(this) }) } if (isPlainObject(properties)) { //将dom转成zepto对象 nodes = $(dom) $.each(properties, function(key, value) { if (methodAttributes.indexOf(key) > -1) nodes[key](value) else nodes.attr(key, value) }) } return dom }
在这个函数中,有两个正规表达式,分别是tagExpanderRE和singleTagRE
tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig; singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/
singleTagRE匹配的是单个的<span></span>诸如此类的标签,而tagExpanderRE匹配的是自闭合标签,如<span/>,但不能是img之类,并将其转成<span><span/>;
从函数中,如果匹配的是单个的html标签,则直接创建该标签并$实例化,将其转变为一个zepto对象,如果匹配的是另一种情况,即将dom转成一个存储这些节点的数组。
然后就是最后一个条件判断了:
if (isPlainObject(properties)) { //将dom转成zepto对象 nodes = $(dom) $.each(properties, function(key, value) { if (methodAttributes.indexOf(key) > -1) nodes[key](value) else nodes.attr(key, value) }) }
先看一下isPlainObject函数,该函数判断是否为一个纯对象:
function isPlainObject(obj) { return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype }
主要的判断在于Object.getPrototypeOf(obj) == Object.prototype;不同的参数调用getPrototypeOf(obj)返回的值不同:
条件判断里的代码需要注意一点,即将dom转成zepto对象,
时间: 2024-10-12 17:08:29