/******************************************************************************
*Zepto核心和dom操作
********************************************************************************/

;var Zepto = (function(){
var undefined,key,$,classList,emptyArray = [],slice = emptyArray.slice,
document = window.document,
elementDisplay = {},classCache = {},
getComputedStyle = document.defaultView.getComputedStyle,
//属性值不需要加px的css样式集;
cssNumber = {'column-count':1,'columns':1,'font-weight':1,'line-height':1,'opacity':1,'z-index':1,'zoom':1},
fragmentRe = /^\s*<(\w+|!)[^>]*>/,

// Used by `$.zepto.init` to wrap elements, text/comment nodes, document,
// and document fragment node types.
elementType = [1,3,8,9,11],

adjacencyOperators = ['after','prepend','before','append'],
//Containers about table
table = document.createElement('table'),
tableRow = document.createElement('tr'),
containers = {
'tr':document.createElement('tbody'),
'tbody':table,'tfoot':table,'thead':table,
'td':tableRow,'th':tableRow,
'*':document.createElement('div')
},
//about download
readyRe = /complete|loaded|interactive/,
//The RegExp of className id and tagName
classSelectorRe = /^\.([\w-]+)$/,
idSelectorRe = /^#([\w-]+)$/,
tagSelectorRe = /([\w-]+)$/,
toString = ({}).toString,
zepto = {},
camelize,uniq,
tempParent = document.createElement('div');

//判断一个元素是否匹配给定的选择器
zepto.matchs = function(element,selector) {
//如果element参数不存在,或者nodeType不为1(元素节点)
if(!element || element.nodeType !== 1) return false
//引用不同浏览器的matchsSelector方法
var matchsSelector = element.webkitMatchesSelector || element.mozMatchesSelector
|| element.oMatchesSelector || element.MatchesSelector;
//如果matchesSelector被浏览器支持,直接返回结果
if(matchsSelector) return matchsSelector.call(element,selector)
//如果浏览器不支持matchesSelector,则将节点放入一个临时的div中,
//再通过selector来查找这个div下的节点集,再判断给定的element是否在节点集中,如果在
//则返回一个非零(非false)的数字
//fall back to performing a selector
var match ,parent = element.parentNode, temp = !parent;
//如果element没有父节点,就将他插入一个临时的div中
if(temp){
(parent = tempParent).appendChild(element);
}
//将parent作为上下文,调用qsa函数,查找Selector匹配结果,返回一个数组,
//获得element在数组中的索引,不存在时为-1;
//通过~运算符~-1转成0,存在时转成一个非0数;返回转后的数;
match = ~zepto.qsa(parent,selector).indexOf(element);
//将插入节点删掉
temp && tempParent.removeChild(element);
return match;
}

//Judge a Object type
//判断书否为函数
function isFunction(value) { return toString.call(value) == "[object Function]" }

//判断是否为对象
function isObject(value) { return value instanceof Object }

//判断是否是一个纯粹的对象
//对于通过字面量定义的对象和new Object的对象返回true
//new Object('aaa')==>false,new Object({'a':1})==>true
function isPlainObject(value) {
var ctor,key;
//判断value书否为对象,为否则返回false;
if(toString.call(value) !== '[object Object]') return false
//如果value的构造函数是函数,则把构造函数的原形对象赋值给ctor;
ctor = (isFunction(value.constructor) && value.constructor.prototype)
//如果ctor不存在或者’isPrototypeOf‘不是ctor的自由属性,返回false;
if(!ctor || !hasOwnProperty.call(ctor,'isPrototypeOf')) return false
//如果key未定义(对象为空)或是value的自由属性,则返回true;
for(key in value);
return key ===undefined || hasOwnProperty.call(value,key)
}

//判断对象是否为数组
function isArray(value) { return value instanceof Array }

//判断对象是否为类数组
function likeArray(value) { return typeof value.length == 'Number' }

//压缩数组,剔除null和undefined,0和''都代表null
function campact(array) { return array.filter(function(item){ return item !== undefined && item !== null })}

//扁平化数组,数组副本
function flatten(array) { return array.length > 0 ? [].concat.apply([],array) : array }

//转换成驼峰命名
camelize = function(str) { return str.replace(/-+(.)/g,function(match,chr){ return chr ? chr.toUpperCase() : '' }) }

//把驼峰命名转换成中划线
function dasherize(str) {
return str.replace(/::/,'/')
.replace(/([A-Z]+)([A-Z][a-z])/g,'$1_$2') //在大写小写之间插入下划线 例如 ADCaaa==>AD_Caaa
.replace(/([a-z]+)([A-Z])/g,'$1_$2') //在小写大写之间插入下划线 例如 adcfA==>adcf_A
.replace(/_/g,'-') //把下划线转换成中划线
.toLowerCase();
}

//数组去重 如果某条数据在数组中的位置和通过indexOf获得的索引值有不同时,就是重复数据
uniq = function(array) { return array.filter(function (item,index) { return array.indexOf(item) == index }) }

//把给定的参数生成正则,并缓存到classCache里
function classRe(name) {
return name in classCache ?
classCache[name] : (classCache[name] = RegExp('(^|\\s)'+name+'(\\s|$)'));
}

//给需要的样式值后面加上px值,除了cssNumber里面指定的
function maybeAddPx(name,value) {
return (typeof value == 'number' && !cssNumber[dasherize(name)]) ? value + 'px' : value;
}

//获得元素的display属性值,把所有的属性值存到缓存区elementDisplay中并值默认设为block;
function defaultDisplay(nodeName) {
var element,display;
//如果elementDisplay中不存在该元素的值
if(!elementDisplay[nodeName]) {
//创建一个临时元素,并添加到body中
element = document.createElement(nodeName);
document.body.appendChild(element);
//获得该元素的最终display值
display = getComputedStyle(element,'').getPropertyValue('display');
//删除临时元素element
element.parentNode.removeChild(element);
//把display的值设为block
display == 'none' && (display = 'block');
//把display值加入到 elementDisplay;
elementDisplay[nodeName] = display;
}
return elementDisplay[nodeName];
}

//根据给定的html字符窜,生成dom node 数组
// `$.zepto.fragment` takes a html string and an optional tag name
// to generate DOM nodes nodes from the given html string.
// The generated DOM nodes are returned as an array.
// This function can be overriden in plugins for example to make
// it compatible with browsers that don't support the DOM fully.
function fragment(html,name) {
//如果name参数没传,就提取html中匹配的第一个标签
if(name === undefined) name = fragmentRe.test(html) && RegExp.$1;
//如果name在containers中不存在,设为*
if(!(name in containers)) name = '*'
//获得容器
var container = containers[name];
//把html插入容器
container.innerHtml = '' + html;
//返回Dom数组,并删除document中的节点
return $.each(slice.call(container.childNodes),function(){
container.removeChild(this);
})
}

//让dom元素继承$.fn的方法
// `$.zepto.Z` swaps out the prototype of the given `dom` array
// of nodes with `$.fn` and thus supplying all the Zepto functions
// to the array. Note that `__proto__` is not supported on Internet
// Explorer. This method can be overriden in plugins.
zepto.Z = function(dom,selector) {
dom = dom || [];
//把dom的__proto__属性指向调用函数zepto.Z(arguments.callee.prototype)的原形,然后把zepto.Z.prototype = $.fn;
//从而使dom继承$.fn上的所有方法
dom.__proto__ = arguments.callee.prototype;
dom.selector = selector || '';
return dom;
}

//判断对象的原形是否是zepto.Z
// `$.zepto.isZ` should return `true` if the given object is a Zepto
// collection. This method can be overriden in plugins.
zepto.isZ = function(object) {
return object instanceof zepto.Z
}

//定义$(selector,context)方法的函数定义
//1)$(selector)获得zepto的dom节点集
//2)$(selector,context)创建一个zepto元素
//3)$(function)实现window.onload事件
// `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
// takes a CSS selector and an optional context (and handles various
// special cases).
// This method can be overriden in plugins.
zepto.init = function (selector,context) {
// If nothing given, return an empty Zepto collection
if(!selector) return zepto.Z()
// If a function is given, call it when the DOM is ready
//如果参数是一个函数,当页面DOM加载完调用
else if(isFunction(selector)) return $(document).ready(selector)
// If a Zepto collection is given, juts return it
//如果selector已经是zepto的节点集,直接返回selector
else if(zepto.isZ(selector)) return selector
else {
var dom;
// normalize array if an array of nodes is given
//如果selector是一个正常的dom 节点数组,剔除数组中的null和undefined;
if (isArray(selector)) dom = campact(selector)
// if a JavaScript object is given, return a copy of it
// this is a somewhat peculiar option, but supported by
// jQuery so we'll do it, too
// 如果selector是一个纯对象,直接将他的副本放到数组中赋值给dom
else if(isPlainObject(selector)) dom = [$.extend({},selector)],selector = null
// wrap stuff like `document` or `window`
// 如果selector的nodeType值属于elementTypes,或selector==window
// 直接把selector放入数组中
else if(elementType.indexOf(selector.nodeType) >= 0 || selector ===window)
dom = [selector],selector = null
// If it's a html fragment, create nodes from it
// 如果selector是一个html的片段,就创建一个元素节点
else if(fragmentRe.test(selector))
dom = zepto.fragment(selector.trim(),RegExp.$1),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.
// 如果selector是CSS选择器,调用zepto.qsa函数获得DOM节点集
else dom = zepto.qsa(document,selector)
// create a new Zepto collection from the nodes found
// 通过找到的DOM,创建一个新的zepto元素集并返回
return zepto.Z(dom,selector)
}
}

// `$` will be the base `Zepto` object. When calling this
// function just call `$.zepto.init, whichs makes the implementation
// details of selecting nodes and creating Zepto collections
// patchable in plugins.
// 把$ 设置为Zepto的基础对象,通过吊$就你实现调用$.zepto.init
$ = function(selector,context) {
return zepto.init(selector,context)
}

// Copy all but undefined properties from one or more
// objects to the `target` object.
// 把一个或多个资源对象的属性拷贝到目标对象上
$.extend = function(target) {
slice.call(arguments,1).forEach(function(source){
var key
for(key in source){
if(source[key] !== undefined){
target[key] = source[key]
}
}
})
return target;
}

// `$.zepto.qsa` is Zepto's CSS selector implementation which
// uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
// This method can be overriden in plugins.
zepto.qsa = function(element,selector) {
var found;
//当element为document,且Selector为id选择器时:
return (element === document && idSelectorRe.test(selector))?
//把通过getElementById找到的值放在数组中,然后返回,如果没有,返回空数组emptyArray
((found = element.getElementById(RegExp.$1))?[found]:emptyArray):
//当element不为元素节点和document时,返回空数组
(element.nodeType !== 1 && element.nodeType !== 9)?emptyArray:
//否则将得到的结果转换为数组再返回
slice.call(
//如果Selector为class选择器,直接调用getElementsByClassName
classSelectorRe.test(selector)?element.getElementsByClassName(selector):
//如果Selector为tag选择器,直接调用getElementsByClassName
tagSelectorRe.test(selector)?element.getElementsByTagName(selector):
//否则调用querySelectorAll
element.querySelectorAll(selector)
)
}

//在nodes的结果中进行过滤
function filtered(nodes,selector) {
return selector === undefined ? $(nodes) : $(nodes).filter(selector);
}

//这个函数在整个库中起着重要作用,判断arg为函数或者为值的情况
//下面很多设置元素属性时的函数都有用到
function funcArg(context,arg,idx,payload) {
return isFunction(arg) ? arg.call(context,idx,payload) : arg
}

//把一些方法挂载到$对象上
$.isFunction = isFunction
$.isObject = isObject
$.isArray = isArray
$.isPlainObject = isPlainObject

//获取某个值在数组中的索引
$.inArray = function(elem,array,i) {
return emptyArray.indexOf.call(array,elem,i)
}

//去除字符串头尾空格
$.trim = function(str){ return str.trim() }

// plugin compatibility
$.uuid = 0

//遍历elements,将每条记录放入callback里处理,把callback返回值不为null和undefined的结果
//保存的一个数组中,最后返回数组
$.map = function(elements,callback) {
var value,values=[],key,i
//如果被遍历的数据是数组或者类数组
if(likeArray(elements)){
for(i = 0;i < elements.length;i++){
value = callback(elements[i],i)
if(value != null) values.push(value)
}
}
//如果是对象
else{
for(key in elements) {
value = callback(elements[key],key)
if(value != null) values.push(value)
}
}
return values
}

//遍历数组,将每条数据作为callback的上下文,传入数据和数据的索引进行处理,如果有一条数据的处理结果
//返回的是false,停止变量,并返回elements
$.each = function(elements,callback) {
var key,i
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;
}

// 定义能被所有zepto的DOM元素使用的方法
// Define methods that will be available on all Zepto collections
zepto.fn = {
// Because a collection acts like an array
// copy over these useful array functions.
// ECMA5 中一些Array(数组)API
forEach:emptyArray.forEach,
reduce:emptyArray.reduce,
push:emptyArray.push,
concat:emptyArray.concat,
indexOf:emptyArray.indexOf,

// `map` and `slice` in the jQuery API work differently
// from their array counterparts
map:function(fn){
return $.map(this,function(el,i){
return fn.call(el,i,el);
})
},
slice:function(){
return $(slice.apply(this,arguments))
},
//DOM 的ready事件
ready:function(callback){
if(readyRe.test(document.readyState)) callback($)
else document.addEventListener('DOMContentLoaded',function(){ callback($)},false)
return this
},
//取集合中对应索引的值,如果没有参数,返回整个集合转换的数组
get:function(idx) {
return idx === undefined ? slice.call(this) : this[idx]
},
//把集合转换成数组
toArray:function(){
return this.get()
},
//获取集合的长度
size:function(){ return this.length },
//将集合从DOM中删除
remove:function(){
return this.each(function(){
if(this.parentNode != null) this.parentNode.removeChild(this)
})
},
//遍历集合,将集合的每一项放入callback中,去掉结果为false的,
//如果明确返回false,遍历就停止了
each:function(){
this.forEach(function(el,idx) {
callback.call(el,idx,el);
})
return this;
},
//过滤集合,返回能与selector匹配的
filter:function(selector) {
return $([].filter.call(this,function(element){
return zepto.matchs(element,selector)
}))
},
//将由selector获得的不同的节点追加到集合中
add:function(selector,context) {
//concat连接两个集合,应为由$()获得的集合是个数组
//uniq去重
return $(uniq(this.concat($(selector,context))))
},
//判断集合中的第一条数据是否和selector匹配
is:function(selector) {
return this.length > 0 && zepto.matchs(this[0],selector);
},
//排除集合里符合selector条件的记录,接收参数可以是function,CSS选择器,dom,nodelist
not:function(selector) {
var nodes = []
//当selector为函数时,safari下的typeof odeList也是function,所以这里需要再加一个判断selector.call !== undefined
if(isFunction(selector) && selector.call !== undefined) {
this.each(function(idx){
//注意这里收集的是selector.call(this,idx)返回结果为false的时候记录
if(!selector.call(this,idx)) nodes.push(this)
})
}
else {
//当selector为字符串的时候,对集合进行筛选,也就是筛选出集合中满足selector的记录
var exclude = typeof selector == 'String' ? this.filter(selector) :
//当selector为nodeList时执行slice.call(selector),注意这里的isFunction(selector.item)是为了排除selector为数组的情况
//当selector为css选择器,执行$(selector)
(likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
this.forEach(function(el){
//筛选出不在excludes集合里的记录,达到排除的目的
if(exclude.indexOf(el) < 0) nodes.push(el)
})
}
//由于上面得到的结果是数组,这里需要转成zepto对象,以便继承其它方法,实现链写
return $(nodes)
},
//根据集合的索引选取对应的记录,当索引为-1时,选择最后一个元素
eq:function (idx) {
return idx === -1 ? this.slice(idx) : this.slice(idx,+idx+1)
},
//取集合中的第一条数据
first:function() {
var el = this[0]
return el && !isObject(el) ? el : $(el)
},
//取集合中的最后一条数据
last:function() {
var el = this[this.length - 1];
return el && !isObject(el) ? el : $(el)
},
//在当集合中的匹配selector的子集
find:function(selector) {
var result
if(this.length === 1) result = zepto.qsa(this[0],selector)
else result = this.map(function(){ result zepto.qsa(this ,selector)})
return $(result)
},
//从当前元素遍历向上找到第一个匹配的元素
closest:function(selector,context) {
var node = this[0]
while(node && !zepto.matchs(node,selector))
node = node !== context && node !== document && node.parentNode
return $(node)
},
//取集合所有父级元素
parents:function(selector) {
var ancestors = [],nodes = this;
while(nodes.length > 0){
nodes = $.map(nodes,function(node){
if((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0){
ancestors.push(node);
return node;
}
})
}
return filtered(ancestors,selector);
},
//获取元素最近的父节点
parent:function(selector) {
return filtered(uniq(this.pluck('parentNode')),selector);
},
//获取每个元素的子节点,并可以通过选择器进行匹配。
children:function(selector) {
return filtered(this.map(function(){ return slice.call(this.children)}), selector);
},
//获取元素的兄弟节点。
siblings:function(selector) {
return filtered(this.map(function(i,el){
//找到当前元素的父元素的子元素,且不等当前元素,就是他所有的相邻元素
return slice.call(el.parent.children).filter(function(child){ return child !== el})
}),selector)
}
//清除集合中每个元素的DOM节点。
empty:function() {
return this.each(function(){ this.innerHTML = '' })
},
//获取集合元素指定的属性值
pluck:function(property) {
return this.map(function(){ return this[property] });
},
//恢复元素display的默认值。
show:function() {
return this.each(function() {
//当内联的display == ‘none’时,清除该属性
this.style.display == 'none' && (this.style.display = null)
//如果该元素在样式表里的属性为none,把display的属性改为默认属性
if(getComputedStyle(this,'').getPropertyValue('display') == 'none') {
this.style.display = defaultDisplay(this.nodeName);
}
})
},
//用新的内容替换集合中的元素。
replaceWith:function(newContent) {
return this.before(newContent).remove();
},
//给集合的每一个元素加一个wrap。
wrap:function(newContent) {
return this.each(function(){
$(this).warpAll($(newContent)[0].cloneNode(false))
})
},
//将所有元素用一个Wrap包装起来。
wrapAll:function(newContent) {
if(this[0]) {
//把wrap插入到第一个元素前面
$(this[0]).before(newContent = $(newContent));
//把集合插入到wrap里
newContent.append(this)
}
return this
},
//移出元素的父节点,并加元素添加到原先自身父节点的位置。
unwrap:function() {
//找到集合内各元素对应的父节点
this.parent().each(function(){
//把父节点用对应的子元素替换
$(this).replaceWith($(this).children())
})
return this;
},
//clone 节点
clone:function() {
return $(this.map(function(){ return this.cloneNode(true) }))
},
//hide,隐藏元素
hide:function() {
return this.css('display','none')
},
//切换元素的显示隐藏,设置setting为true,显示元素,反之则隐藏元素。
toggle:function(setting) {
//当setting不存在时,display为none时,启动show(),否则hide()
//当setting为true时show(),为false时hide()
return (setting === undefined ? this.css('display') == 'none' : setting) ? this.show() : this.hide()
},
//获取集合中每个元素的前一个兄弟节点,可以传入选择器参数。
prev:function() { return $(this.pluck('previousElementSibling')) },
//获取下一个兄弟节点,可以传入一个选择器参数。
next:function() { return $(this.pluck('nextElementSibling'))},
//读写元素的innerHTML值, value为空,返回首个元素的innerHTML.若value不为空,则修改每个元素的innerHTML值。
html:function(html) {
//判断html是否定义
return html === undefined ?
//如果未定义,获取集合中第一个元素的html
(this.length>0 ? this[0].innerHTML : null) :
//如果html定义了
//html是字符窜,直接插入到每条记录中国
//如果是函数,则将当前记录作为上下文,调用该函数,且传入该记录的索引和原始innerHtml作为参数
this.each(function(idx) {
var originHtml = this.innerHTML;
$(this).empty().append( funcArg(this,html,idx,originHtml) )
})
},
//读写元素的text内容。
text:function(text) {
//如果不给定text参数,则为获取功能,集合长度大于0时,取第一条数据的textContent,否则返回null,
//如果给定text参数,则为集合的每一条数据设置textContent为text
return text === undefined ?
(this.length >0 ? this[0].textContent : null) :
this.each(function(){ this.textContent = text })
},
//读或写DOM属性。当没有给出value值的时候,从集合的第一个元素中读取特定属性;
//当给出value值的时候,修改集合中每个元素的特定属性值;
//当value值为null,则删除属性。多个属性可用对象来传递。
attr:function(name,value) {
var result
return (typeof name == 'String' && value === undefined) ?
//当name存在且为字符串,value不存在,表示获得第一条记录的属性
//集合为空或者node不是元素类型,返回undefined
(this.length == 0 || this[0].nodeType !== 1 ? undefined :
//如果取的是input的value时如下:
name == 'value' && this[0].nodeName == 'INPUT' ? this[0].value :
//如果浏览器不支持getAttribute,就用this[0][name]
(!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
) :
//name 不为字符串,或者value存在时
this.each(idx) {
if(this.nodeType !== 1) return
//如果name是对象,则给每条记录设置属性
if(isObject(name)) for (var key in name) this.setAttribute(key name[key])
//如果name只是一个普通的属性字符串,用funcArg来处理value是值或者function的情况最终返回一个属性值
//如果funcArg函数返回的是undefined或者null,则相当于删除元素的属性
else this.setAttribute(name,funcArg(this,value,idx,this.getAttribute(name)))
}
},
//移出所有元素中指定的属性。
removeAttr:function(name) {
return this.each(function(){ if (this.nodeType === 1) this.removeAttribute(name) })
},
//这个方法在读取像checked和selected等在不同时间可能随着用户行为而变化的属性值时,方法更优先使用。
//获取第一条数据的指定的name属性或者给每条数据添加自定义属性,注意和setAttribute的区别
prop:function(name,value) {
//没有给定value时,为获取,给定value则给每一条数据添加,value可以为值也可以是一个返回值的函数
(value === undefined) ?
(this[0] ? this[0][name] : undefined) :
this.each(function(idx) {
this[name] = funcArg(this,value,idx,this[name])
})
},
//读写DOM元素的data-*属性。
data:function(name,value) {
//通过调用attr方法来实现获取与设置的效果,注意attr方法里,当value存在的时候,
//返回的是集合本身,如果不存在,则是返回获取的值
var data = this.attr('data-'+dasherize(name),value);
return (data !== null) ? data : undefined;
},
//读写元素的value值。
val:function(value) {
//如果value存在时,给每条记录设置value
//当value不存在时,获取value值
return (value === undefined) ?
(this.length>0 ? this[0].value : undefined) :
this.each(function(idx) {
this.value = funcArg(this,value,idx,this.value)
})
},
//获取元素在文档中的位置,返回值属性包含:top, left, width and height。
offset:function(){
if(this.length ===0) return null;
//如果集合不为空,获得第一个记录的位置矩阵
var obj = this[0].getBoundingClientRect();
//返回一条记录的offset,包括offsetTop,offsetLeft,offsetWidth,offsetHeight
return {
//在非ie下,obj.left相当对于窗口上部的距离,window.pageXOffset代表滚动的距离
left:obj.left+window.pageXOffset,
top:obj.top+window.pageYOffset,
width:obj.width,
height:obj.height
}
},
//读写DOM元素的CSS属性。
css:function(property,value) {
//如果value未定义,property存在且为字符串,返回集合第一条记录的对应样式值
if(value === undefined && typeof property == 'string') {
return (this.length === 0
? undefined
: this[0].style[camelize(property)] || getComputedStyle(this[0],'').getPropertyValue(property))
}
var css = '',key
//当property为对象时
for(key in property) {
//当一对map的value为空时,删除该属性
if(typeof property[key] == 'string' && property[key] == '')
this.each(function(){ this.style.removeProperty(dasherize(key))})
//否则给所有的记录添加改样式
else
css += dasherize(key) + ":" + maybeAddPx(key,property[key]) + ";"
}
//当property存在,且value也存在
if(typeof property == 'string') {
//当value值为空时
if(value === '')
this.each(function(){ this.style.removeProperty(dasherize(property))})
//否则给所有的记录添加改样式
else
css += dasherize(property) + ":" + maybeAddPx(property,value) + ";"
}
//通过cssText的方法绑定样式
return this.each(function(){ this.style.cssText +=";"+css })
},
//获取元素的位置(在父节点中与其他兄弟节点比较的位置)。
index:function(element) {
//这里的$(element)[0]是为了将字符串转成node,因为this是个包含node的数组
//当不指定element时,取集合中第一条记录在其父节点的位置
//this.parent().children().indexOf(this[0])这句很巧妙,和取第一记录的parent().children().indexOf(this)相同
return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
},
//检查集合中首个元素是否含有指定类名,返回一个bealoon值。
hasClass:function(name) {
if(this.length < 1) return false
//classRe用于生成正则
else return classRe(name).test(this[0].className)
},
//给集合中每个元素添加类名,多个类名可用空格分隔开。
addClass:function(name) {
return this.each(function(idx) {
classList = []
var cls = this.className,newName = funcArg(this,name,idx,cls)
//当name中同时有多个类名时
//先通过空格把name切分成数组
newName.split(/\s+/g).forEach(function(klass){
//如果当前记录不含klass类名,把klass加入到classLisst里
if(!(this.hasClass(klass))) classList.push(klass)
},this)//forEach中接收第二个参数this改变回调函数里this的指向
classList.length && this.className += (cls ? " " : "") + classList.join(" ")
})
},
//移出所有元素中指定的类。
removeClass:function(name) {
return this.each(function(idx) {
//如果name未定义,把class设为空
if(name === undefined)
return this.className = ''
classList = this.className
funcArg(this,name,idx,classList).split(/\s+/g).forEach(function(klass){
//如果有klass能和classList匹配,就替换成空格
classList = classList.replace(classRe(klass),' ')
})
this.className = classList.trim()
})
},
//切换元素的类名,若存在,则删除该类名,反之,则添加该类名。
toggleClass:function(name when) {
return this.each(function(idx) {
var newName = funcArg(this,name,idx,this.className)
;(when === undefined ? !$(this),hasClass(name) : when) ?
$(this).addClass(newName) : $(this).removeClass(newName)
})
}

}

// Generate the `width` and `height` functions
// 生成width和height 的函数
['width','height'].forEach(function(dimension) {
$.fn[dimension] = function(value) {
//把数组中的值的第一个字母转换成大写,并返回到Dimension中
var offset,Dimension = dimension.replace(/./,function(m) { return m[0].toUpperCase() });
//当没有传参数时
if(value === undefined) {
//当this[0]为window时,通过inner的方法获得宽高
return this[0] == window ? window.['inner'+Dimension] :
//当this[0]为document时,通过offset获得高宽
this[0] == document ? document.documentElement['offset'+Dimension] :
(offset = this.offset()) && offset[dimension]
//当传了参数时 设置元素的高宽
} else {
return this.each(function(idx) {
var el = $(this)
el.css(dimension,funcArg(this,value,idx,el[dimension]()))
})
}
}
})

// insert function 实现节点插入的函数
//@operator 操作符下标 0=>after,1=>prepend,2=>before,3=>append;
//@target 文档中已经存在的基节点
//@node 要插入的节点
function insert(operator,target,node) {
//确定要插入的父节点,如果operator为0、2就是target本身,否则就为target的parentNode
var parent = (operator%2) ? target : target.parentNode;
//如果parent存在就添加,否则就删除node
parent ? parent.insertBefore(node,
!operator ? target.nextSibling : //operator = 0 :after
operator == 1 ? parent.firstChild : //operator = 1 :prepend
operator == 2 ? target : //operator = 2 :before
null) : //operator = 3 :append
$(node).remove
}
//让node和node的子元素都经过traverseNode的处理
function traverseNode(node,fun) {
fun(node);
for(var key in node.childNodes) traverseNode(node.childNodes[key],fun)
}
// Generate the `after`, `prepend`, `before`, `append`,
// `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
adjacencyOperators.forEach(function(key,operator) {
//实现 `after`, `prepend`, `before`, `append`
$.fn[key] = function() {
// arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
// 参数可以是集合,集合数组,zepto节点,html字符串
// 先把参数转换成zepto的集合
var nodes = $.map(arguments,function(n){ return isObject(n) ? n : zepto.fragment(n) });
if(nodes.length < 1) return this;
//当nodes的长度大于0时
var size = this.length, copyByClone = size > 1, inReverse = operator < 2;
return this.each(function(index,target) {
for(var i = 0;i<nodes.length;i++) {
//保证节点插入文档后顺序不变
var node = nodes[inReverse ? nodes.length-i-1 : i]
//插入节点后,如果被插入的节点是SCRIPT,则执行里面的内容并将window设为上下文
traverseNode(node,function(node) {
if(node.nodeName !== null && node.nodeName.toUpperCase() === 'SCRIPT' && (!node.type || node.type = 'text/javascript'))
window['evel'].call(window,node.innerHTML)
})
//当基集合的长度大于1时,且index小于nodes.length-1时,就要克隆一个node
if(copyByClone && index < nodes.length - 1) node = node.cloneNode(true) ;
//插入节点
insert(operator,target,node)
}
})

}
//实现`insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
$.fn[(operator%2) ? key + 'To' : 'insert' + (operator ? 'Before' : 'After')] = function(html) {
$(html)[key](this)
return this
}
})

//把构造函数Z的原形设置为$.fn
zepto.Z.prototype = $.fn;

// Export internal API functions in the `$.zepto` namespace
// 把内部的API暴露出来
zepto.camelize = camelize;
zepto.uniq = uniq;
$.zepto = zepto;
return $;
}())
// If `$` is not yet defined, point it to `Zepto`
// 如果$还未定义,把Zepto赋值给$;
window.Zepto = Zepto;
'$' in window || window.$ = Zepto

Zepto源码解读的更多相关文章

  1. 第二十五课:jQuery.event.trigger的源码解读

    本课主要来讲解jQuery.event.trigger的源码解读. trigger = function(event, data, elem, onlyHandlers){ if(elem & ...

  2. 读 zepto 源码之工具函数

    Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目标对象的同名属性会被源对象的 ...

  3. 读Zepto源码之集合操作

    接下来几个篇章,都会解读 zepto 中的跟 dom 相关的方法,也即源码 $.fn 对象中的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码 ...

  4. 读 Zepto 源码之集合元素查找

    这篇依然是跟 dom 相关的方法,侧重点是跟集合元素查找相关的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zept ...

  5. 读zepto源码之工具函数

    读zepto源码之工具函数 Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目 ...

  6. 读 Zepto 源码系列

    虽然最近工作中没有怎么用 zepto ,但是据说 zepto 的源码比较简单,而且网上的资料也比较多,所以我就挑了 zepto 下手,希望能为以后阅读其他框架的源码打下基础吧. 源码版本 本文阅读的源 ...

  7. fastclick.js源码解读分析

    阅读优秀的js插件和库源码,可以加深我们对web开发的理解和提高js能力,本人能力有限,只能粗略读懂一些小型插件,这里带来对fastclick源码的解读,望各位大神不吝指教~! fastclick诞生 ...

  8. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  9. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

随机推荐

  1. 【HTML】Beginner8:Table

    1.Table     Abused to lay out pages    The correct use for tables is to do exactly what you would ex ...

  2. bzoj 1951 [Sdoi2010]古代猪文(数论知识)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1951 [思路] 一道优(e)秀(xin)的数论题. 首先我们要求的是(G^sigma{ ...

  3. NOIP2001 一元三次方程求解

    题一  一元三次方程求解(20分) 问题描述 有形如:ax3+bx2+cx+d=0  这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d  均为实数),并约定该方程存在三个不同实根(根的范 ...

  4. sap判断条件

    EQ  等于=  等于NE  不 等于<>  不 等于><  不 等于LT  小 于<  小于LE  小 于等于<=  小 于等于GT  大 于>  大于GE ...

  5. 【Kafka入门】Kafka入门第一篇:基础概念篇

    Kafka简介 Kafka是一个消息系统服务框架,它以提交日志的形式存储消息,并且消息的存储是分布式的,为了提供并行性和容错保障,消息的存储是分区冗余形式存在的. Kafka的架构 Kafka中包含以 ...

  6. HDOJ-ACM2035(JAVA) 人见人爱A^B

    这道题的巧妙方法没有想出来,但是算是优化的暴力破解吧.Accepted import java.io.BufferedInputStream; import java.util.Scanner; pu ...

  7. (Step by Step)How to setup IP Phone Server(VoIP Server) for free.

    You must have heard about IP Phone and SIP (Software IP Phone).Nowadays standard PSTN phone are bein ...

  8. AJAX中文乱码PHP完美解决(IE和Firefox兼容)

    最近在做一个项目,遇到AJAX中文乱码问题,经过一个下午的努力终于完美解决,现将心得写下来,希望对那些还困绕在这个问题而头痛不已的人们有所帮助. 众所周知,使用AJAX传送和接收中文参数时,如果不在客 ...

  9. sql server 分布式事务

    使用分布式事务刚好可以解决集群同时更新多台SQL SERVER数据库,要么全部成功,要么全部回滚的需要. 原来微软早考虑到此方面的问题了. 下面背书,贴出微软官网上面的帮助文档: 分布式事务跨越两个或 ...

  10. linux安装svn服务器(yum方式)

    1.查看yum是否安装         在终端中输入yum即可如果已经安装,会显示yum的参数         如果没有安装,会提示yum未安装或无效命令…… 2.安装svnyum -y instal ...