zepto源码研究 - zepto.js-4(常用的工具)

时间:2022-09-08 21:11:32

$.each:

/**
* 以集合每一个元素作为上下文,来执行回调函数
* @param elements
* @param callback
* @returns {*}
*/
$.each = function(elements, callback){
var i, 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
}

这里的elements可以是数组或者对象,如果是对象,则会将其原型里面的属性也遍历出来,最后返回elments本身,如果回调函数返回了false,则终止循环

remove:

/**
* 删除元素集
* 原理 parentNode.removeChild
* @returns {*}
*/
remove: function(){
//遍历到其父元素 removeChild
return this.each(function(){
if (this.parentNode != null)
this.parentNode.removeChild(this)
})
},

这里的重点是parentNode.removeChild(this); 如果是没有父节点的这里不会执行。

is:

//返回集合中的第1条记录是否与selector匹配
is: function(selector){
return this.length > 0 && zepto.matches(this[0], selector)
}

例如$("#id").is(".hasClass"); 实际就是调用matches进行匹配

not: 

//排除集合里满足条件的记录,接收参数为:css选择器,function, dom ,nodeList
not: function(selector){
var nodes=[]
//当selector为函数时,safari下的typeof nodeList也是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 excludes = 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 (excludes.indexOf(el) < 0) nodes.push(el)
})
}
return $(nodes)//由于上面得到的结果是数组,这里需要转成zepto对象,以便继承其它方法,实现链写
},

这里首先判断selector是否为函数,如果是,则遍历执行函数,如果返回false,则push到数组中

如果css选择字符串则调用this.filter(seelctor),这里有个小技巧使得not和filter相互调用

如果是数组或对象,则直接返回$(他自己)

最后遍历this,只要不是在excludes里面的都是满足条件的

has:

/*
接收node和string作为参数,给当前集合筛选出包含selector的集合
isObject(selector)是判断参数是否是node,因为typeof node == 'object'
当参数为node时,只需要判读当前记当里是否包含node节点即可
当参数为string时,则在当前记录里查询selector,如果长度为0,则为false,filter函数就会过滤掉这条记录,否则保存该记录
*/
has: function(selector){
return this.filter(function(){
return isObject(selector) ?
$.contains(this, selector) :
$(this).find(selector).size()
})
},

重点提示下:这里的this如果也满足selector,则最后返回的结果集里也会有this  

show:

 
/**
* 获取元素的默认display属性
* 是为了兼容什么?
* @param nodeName
* @returns {*}
*/
function defaultDisplay(nodeName) {
var element, display
if (!elementDisplay[nodeName]) { //缓存里没有 element = document.createElement(nodeName)
document.body.appendChild(element)
display = getComputedStyle(element, '').getPropertyValue("display")
element.parentNode.removeChild(element) // display == "none",设置成blaock,即隐藏-显示
display == "none" && (display = "block") elementDisplay[nodeName] = display //TODO:缓存元素的默认display属性,缓存干嘛?
}
return elementDisplay[nodeName]
}

/**
* 展示
* @returns {*}
*/
show: function(){
return this.each(function(){
//清除内联样式display="none"
this.style.display == "none" && (this.style.display = '')
//计算样式display为none时,重赋显示值
if (getComputedStyle(this, '').getPropertyValue("display") == "none")
this.style.display = defaultDisplay(this.nodeName)
//defaultDisplay是获取元素默认display的方法
})
},

this.style.display = ' '是清除元素的style里面的display样式,恢复元素的默认样式。

getComputedStyle(dom)能获取dom的所有css样式,第二个参数可以不传

getComputedStyle(dom,":after")能获取dom的:after伪类的所有css样式(这里只谈移动端)

详情请看:http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/

如果清除了style里面的display属性还是无效的话,直接显式的给display赋默认值,defaultDisplay的内部实际是在document里面新添加一个元素,来获取默认值的。

css:

/**
* 读写样式 写:内联样式 读:计算样式
* 原理 读:elment[style]/getComputedStyle, 写 this.style.cssText 行内样式设值
* @param property String/Array/Fun
* @param value
* @returns {*}
*/
css: function(property, value){
//只有一个传参,读
if (arguments.length < 2) {
var computedStyle, element = this[0]
if(!element) return
//getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值。返回的是一个CSS样式声明对象([object CSSStyleDeclaration]),只读
//读到计算样式
computedStyle = getComputedStyle(element, '')
//设置样式
if (typeof property == 'string')// 字符串
//优先读行内样式,再读计算样式,行内样式级别最高? TODO:似乎有bug,如果设置了!important 呢
return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
else if (isArray(property)) { //数组
var props = {}
$.each(property, function(_, prop){ //遍历读取每一条样式,存入JSON,返回
props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
})
return props
}
} //如果是写
var css = ''
if (type(property) == 'string') {
if (!value && value !== 0) //null,undefined时,删掉样式
this.each(function(){
//删除 dasherize是将字符串转换成css属性(background-color格式)
this.style.removeProperty(dasherize(property))
})
else
//‘-’格式值 + px单位
css = dasherize(property) + ":" + maybeAddPx(property, value)
} else {
for (key in property) //是对象时
if (!property[key] && property[key] !== 0)
//当property[key]的值为null/undefined,删除属性
this.each(function(){ this.style.removeProperty(dasherize(key)) })
else
//‘-’格式值 + px单位
css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'
} //设值 //TODO: this.style.cssText += 未考虑去重了
return this.each(function(){ this.style.cssText += ';' + css })
},

判断只传了一个参数:arguments.length < 2 或者 1 in  arguments,

流程大致如下:

1:判断参数,如果是一个参数则为只读模式

1.2:如果property为字符串,则 直接获取元素的css属性值

1.3:如果property为数组,则this.each遍历数组,获取每个属性的value值并形成props对象返回

2:若有2个参数,为写模式

2.1:如果property为字符串,则style.cssText+= property:value(这里的处理没有去重,但本人测了一下,这并不影响页面的渲染)

2.2:如果property为对象,则循环遍历property

这里有几个函数要提一下:

camelize() 将带“—”的转为驼峰命名例如“background-color”转为“backgroundColor”,对象属性是必须驼峰命名的。

dasherize()  将“backgroundColor”转为“background-color”,内部实现是用正则表达式匹配

style.removeProperty  删除style中的某个属性

style.setProperty(property,value,priority)  设置style中的某个属性,priority可取“important” ,(不太明白为什么zepto不用这个方法,望高人指教)

maybeAddPx (property,value):根据property类型给value加上“px”后缀

html:


/**
* 处理 arg为函数/值
* 为函数,返回函数返回值
* 为值,返回值
* @param context
* @param arg
* @param idx
* @param payload
* @returns {*}
*/
function funcArg(context, arg, idx, payload) {
return isFunction(arg) ? arg.call(context, idx, payload) : arg
}
/**
* 读写元素HTML内容
* 原理 通过innerHTML读内容,append()写内容
* @param html
* @returns {*|string|string|string|string|string}
*/
html: function(html){
return in arguments ?
this.each(function(idx){
var originHtml = this.innerHTML //记录原始的innerHTMl
//如果参数html是字符串直接插入到记录中,
//如果是函数,则将当前记录作为上下文,调用该函数,且传入该记录的索引和原始innerHTML作为参数
$(this).empty().append( funcArg(this, html, idx, originHtml) )
}) :
( in this ? this[].innerHTML : null)
},

html():不传参数则获取元素的innerHTML,

html("<div></div>"):设置元素的innerHTML

html(function(){....}):可传入方法,返回值设置为元素的innerHTML

这里的funcArg的功能是判断html为函数则以this为上下文,以idx,originHtml为参数执行函数

text:

/**
* 读写元素文本内容
* 原理: 通过 textContent 读写文本
* @param text
* @returns {*}
*/
text: function(text){
return in arguments ?
this.each(function(idx){ //传参遍历写入
var newText = funcArg(this, text, idx, this.textContent)
this.textContent = newText == null ? '' : ''+newText
}) :
( in this ? this[].textContent : null) //未传参读
},

  




														
		

zepto源码研究 - zepto.js-4(常用的工具)的更多相关文章

  1. zepto源码研究 - zepto&period;js - 1

    简要:网上已经有很多人已经将zepto的源码研究得很细致了,但我还是想写下zepto源码系列,将别人的东西和自己的想法写下来以加深印象也是自娱自乐,文章中可能有许多错误,望有人不吝指出,烦请赐教. 首 ...

  2. zepto源码研究 - deferred&period;js(jquery-deferred&period;js)

    简要:zepto的deferred.js 并不遵守promise/A+ 规范,而在jquery v3.0.0中的defer在一定程度上实现了promise/A+ ,因此本文主要研究jquery v3. ...

  3. zepto源码研究 - fx&lowbar;methods&period;js

    简要:依赖fx.js,主要是针对show,hide,fadeIn,fadeOut的封装. 源码如下: // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zept ...

  4. zepto源码研究 - fx&period;js

    简要:zepto 提供了一个基础方法animate来方便我们运用css动画.主要针对transform,animate以及普通属性(例如left,right,height,width等等)的trans ...

  5. zepto源码研究 - zepto&period;js &lpar;zepto&period;init&rpar;

    简要:当我们用$()时,便会直接调用zepto.init 生成zepto对象,那zepto.init是如何根据不同类型的参数来生产指定对象呢? zepto.init = function(select ...

  6. zepto源码研究 - zepto&period;js - 6&lpar;模板方法&rpar;

    width  height  模板方法   读写width/height ['width', 'height'].forEach(function(dimension){ //将width,hegih ...

  7. zepto源码研究 - ajax&period;js(&dollar;&period;ajax具体流程分析)

    简要:$.ajax是zepto发送请求的核心方法,$.get,$.post,$.jsonp都是封装了$.ajax方法.$.ajax将jsonp与异步请求的代码格式统一起来,内部主要是先处理url,数据 ...

  8. zepto源码研究 - ajax&period;js(&dollar;&period;ajaxJSONP 的分析)

    简要:jsonp是一种服务器和客户端信息传递方式,一般是利用script元素赋值src来发起请求.一般凡是带有src属性的元素发起的请求都是可以跨域的. 那么jsonp是如何获取服务器的数据的呢? j ...

  9. zepto源码研究 - zepto&period;js - 5&lpar;dom属性管理&rpar;

    index: $.fn = {...... indexOf: emptyArray.indexOf,} index: function(element){ //这里的$(element)[0]是为了将 ...

随机推荐

  1. web端跨域调用webapi

    在做Web开发中,常常会遇到跨域的问题,到目前为止,已经有非常多的跨域解决方案. 通过自己的研究以及在网上看了一些大神的博客,写了一个Demo 首先新建一个webapi的程序,如下图所示: 由于微软已 ...

  2. 利用IdentityServer3在ASP&period;NET 5和Angular中实现OAuth2 Implicit Flow

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:之前介绍过的IdentityServer3虽然是基于Katana开发的,不过同样可以托 ...

  3. Spring AOP Schema aop&colon;config、tx&colon;advice

    Spring AOP Schema  aop:config.tx:advice 一.      利用aop:config标签实现AOP 首先看个例子,如下 接口代码: package com.lei. ...

  4. 武汉Uber优步司机奖励政策(2月1日~2月7日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. GitHub Desktop安装异常解决

    为了更好的共同学习,共同进步,哥们推荐我使用GitHub记录自己每天的学习记录,当下很火的提供一个分布式的版本控制系统(Git)服务的网站,GitHub提供GitHub Desktop桌面程序方便协同 ...

  6. File I&sol;O

    File I/O Introduction     We'll start our discussion of the UNIX System by describing the functions ...

  7. vue切换路由页面内容没有重载

    项目中遇到这样一个问题: 在一个地方填了一个申请的表单,需要在另一个页面的列表上显示出来这条申请的数据,但是由于vue的缓存,在切换路由时列表上并没有及时更新数据,解决方法如下: vue路由切换时页面 ...

  8. (转载)关于一些对location认识的误区

    原文:https://www.cnblogs.com/lidabo/p/4169396.html 关于一些对location认识的误区 1. location 的匹配顺序是“先匹配正则,再匹配普通”. ...

  9. elsearch

    1. ElasticSearch是性能优化的分布式全文搜索引擎,存储数据的载体是文档(Document),它的优势在于搜索速度快和支持聚合操作,在更新文档时,基本上能够达到实时搜索.ElasticSe ...

  10. Confluence 6 从外部目录中同步数据手动同步缓存

    你可以通过单击用户目录(User Directories)界面中的同步(Synchronize)按钮,手动进行同步.如果一个同步进程已经正在同步的过程中的话,你就不能在上一个同步进程完成之前重新进行同 ...