zepto源码研究 - zepto.js - 5(dom属性管理)
index:
$.fn = {
......
indexOf: emptyArray.indexOf,
}
index: function(element){
//这里的$(element)[0]是为了将字符串转成node,因为this是个包含node的数组
//当不指定element时,取集合中第一条记录在其父节点的位置
//this.parent().children().indexOf(this[0])这句很巧妙,和取第一记录的parent().children().indexOf(this)相同
return element ? this.indexOf($(element)[]) : this.parent().children().indexOf(this[])
},
obj.index(element) : 如果element有,则obj作为一个数组,取element在这个obj中的索引。如果element没有,则此函数的意思是取dom节点所在父类中的索引。
<div id="first" class="test">
<div id="second" class="test">
</div>
</div> 测试: $(".test").index($("#second")); $(".test").index($("#second")[]); $(".second").index();
-
$("#second").index();
hasClass:
/**
* 是否含有指定的类样式
* @param name
* @returns {boolean}
*/
hasClass: function(name){
if (!name) return false
//some ES5的新方法 有一个匹配,即返回true 。
return emptyArray.some.call(this, function(el){
//this是classRE(name)生成的正则
return this.test(className(el))
}, classRE(name))
},
array.some(function(curentValue,index,arr){},thisValue),thisValue作为回调函数中的this,若没有指定thisValue,则回调函数中的this为undefined,
className(el) :一般取el.className(svg除外),classRE(name) 生成一个name的正则表达式,
test是RegExp的方法,参数是字符串,返回值是boolean类型。
match是String的方法,参数是正则表达式,返回值是数组。
classRE:
/**
* 将参数变为正则表达式
* @param name
* @returns {*}
*/
function classRE(name) {
//classCache,缓存正则
//TODO 缓存可以理解,但应该在重复使用第二次时再缓存吧,直接缓存?
return name in classCache ?
classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
}
className:
/**
* 对SVGAnimatedString的兼容?
* @param node
* @param value
* @returns {*}
*/
function className(node, value){
var klass = node.className || '',
svg = klass && klass.baseVal !== undefined if (value === undefined) return svg ? klass.baseVal : klass
svg ? (klass.baseVal = value) : (node.className = value) //class设值
}
addClass:
/**
* 增加一个或多个类名
* @param name 类名/空格分隔的类名/函数
* @returns {*}
*/
addClass: function(name){
if (!name) return this //遍历增加
return this.each(function(idx){
//已存在,返回
if (!('className' in this)) return
classList = []
var cls = className(this), newName = funcArg(this, name, idx, cls) //修正类名,处理name是函数,SVG动画兼容的情况 //多个类,空格分隔为数组
newName.split(/\s+/g).forEach(function(klass){
if (!$(this).hasClass(klass)) classList.push(klass)
}, this) //设值 如果所有的都是重复的,就不会执行
classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
})
},
addClass(name)的name参数可以为函数,newName.split(/\s+/g) :根据空格分为数组,这是一个技巧,这里是先对newName过滤,把重复的class去掉,
然后以字符串的形式连接原来的className并赋值给dom
removeClass:
/**
*删除一个或多个类名 同addClass
* 原理: className.repalce 替换撒谎年初
* @param name 类名/空格分隔的类名/函数
* @returns {*}
*/
removeClass: function(name){
return this.each(function(idx){
if (!('className' in this)) return
if (name === undefined) return className(this, '')
classList = className(this)
funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
//替换删除
classList = classList.replace(classRE(klass), " ")
})
className(this, classList.trim())
})
},
这里要删除一个字符串里面的指定的子字符串,可以使用replace(classRE," ")
toggleClass:
/**
* 切换类的添加或移除
* 原理 如果存在,即removeClass移除,不存在,即addClass添加
* @param name 类名/空格分隔的类名/函数
* @param when
* @returns {*}
*/
toggleClass: function(name, when){
if (!name) return this
return this.each(function(idx){
var $this = $(this), names = funcArg(this, name, idx, className(this))
names.split(/\s+/g).forEach(function(klass){
// 这里的when可以作为标记,来判断是add还是remove
(when === undefined ? !$this.hasClass(klass) : when) ?
$this.addClass(klass) : $this.removeClass(klass)
})
})
},
attr:
/**
* 设置属性
* @param node
* @param name
* @param value
*/
function setAttribute(node, name, value) {
//value为null/undefined,处理成删除,否则设值
value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
} /**
* 元素的HTML属性读写
* 读:原理是getAttribute
* 写:原理是setAttribute
* @param name
* @param value
* @returns {undefined}
*/
attr: function(name, value){
var result;
//仅有name,且为字符串时,表示读
return (typeof name == 'string' && !( in arguments)) ?
//$是空的 或里面的元素非元素,返回undefined
(!this.length || this[].nodeType !== ? undefined :
//直接用getAttribute(name)读,
(!(result = this[].getAttribute(name)) && name in this[]) ? this[][name] : result
) : //否则是写,不管name为对象{k:v},或name value 都存在
this.each(function(idx){
if (this.nodeType !== ) return //非元素
//如果name为对象,批量设置属性
if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
//处理value为函数/null/undefined的情况
else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
})
},
经整理后如下:
//如果只有一个参数,且name为string类型,则此函数为读模式
if((typeof name == 'string' && !( in arguments)) ){
if(!this.length || this[].nodeType !== ) return undefined; if((result = this[].getAttribute(name))){
// 如果dom有这个属性,则返回
return result;
}else{
// 如果dom没有这个属性,则从内存中获取并返回
if(name in this[]) return this[][name];
}
}else{
this.each(function(idx){
if (this.nodeType !== ) return //非元素
//如果name为对象,批量设置属性
if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
//处理value为函数/null/undefined的情况,这里的funcArg函数在整个zepto中复用了很多次,
// 考虑参数为函数的情况在很大方法中出现,setAttribute处理value为null的情况,实际就是removeAttribute
else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
})
}
data:
/**
* 设置自定义数据
* 注意与jQuery的区别,jQuery可以读写任何数据类型。这里原理是H5的data-,或直接setAttribute/getAttribute,只能读写字符串
* @param name
* @param value
* @returns {*}
*/
/*getAttribute/setAttribute可以操作所有的dataset内容,dataset内容只是attribute的一个子集,
特殊就特殊在命名上了。那么为什么我们还要用data-*呢,
一个最大的好处是我们可以把所有自定义属性在dataset对象中统一管理,遍历啊神马的都哦很方便,
而不至于零零散散了,所以用用还是不错的。*/
data: function(name, value){
var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() var data = ( in arguments) ?
this.attr(attrName, value) :
this.attr(attrName) return data !== null ? deserializeValue(data) : undefined
},
函数中的第一步是将驼峰命名的name转化为带“ - ”的小写命名:
var name = "aTcF";
name = name.replace(/([A-Z])/g, '-$1').toLowerCase();
console.log(name);
结果: a-tc-f
这里有一个不太懂的地方,就是如果value为对象的话,这里直接使用attr(attrName,value),最终属性值为"[object Object]",取出后直接JONS.parse会出错
所以我觉得attr里面的value应该再校验一下是否为对象,若是,则value = JSON.stringify(value);
这里存取自定义属性,可以用dateset 并兼容attr,例子如下:
function data(name, value){
var attrName = name.replace(capitalRE, '-$1').toLowerCase();
if(isObject(value)) value = JSON.stringify(value);
if(this[0].dataset){
var data = (1 in arguments) ?
this[0].dataset[attrName] = value :
this[0].dataset[attrName];
}else{
attrName = 'data-'+attrName;
var data = (1 in arguments) ?
this.attr(attrName, value) :
this.attr(attrName)
}
return data !== null ? deserializeValue(data) : undefined
}
val:
/**
* 适合表单元素读写
* 写: 写入每个元素 element.value
* 读: 读第一个元素
* @param value 值/函数
* @returns {*}
*/
val: function(value){
return 0 in arguments ?
//只有一个参数是写,
this.each(function(idx){
this.value = funcArg(this, value, idx, this.value)
}) :
//如果是读
(this[0] && (this[0].multiple ? //对多选的select的兼容处理,返回一个包含被选中的option的值的数组
$(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
this[0].value)
)
},
这里的this[0].multiple 可以判断是否为多选的select,select节点的value属性与被选中的option的value属性是相关联的。如下例子
select#third选中的option的value为1
console.log($("#third")[0].value);
结果:1 console.log($("#third")[0].value = 2);
select#third选中的option的value变为2
结果:2
zepto源码研究 - zepto.js - 5(dom属性管理)的更多相关文章
- zepto源码研究 - zepto.js - 1
简要:网上已经有很多人已经将zepto的源码研究得很细致了,但我还是想写下zepto源码系列,将别人的东西和自己的想法写下来以加深印象也是自娱自乐,文章中可能有许多错误,望有人不吝指出,烦请赐教. 首 ...
- zepto源码研究 - fx_methods.js
简要:依赖fx.js,主要是针对show,hide,fadeIn,fadeOut的封装. 源码如下: // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zept ...
- zepto源码研究 - deferred.js(jquery-deferred.js)
简要:zepto的deferred.js 并不遵守promise/A+ 规范,而在jquery v3.0.0中的defer在一定程度上实现了promise/A+ ,因此本文主要研究jquery v3. ...
- zepto源码研究 - fx.js
简要:zepto 提供了一个基础方法animate来方便我们运用css动画.主要针对transform,animate以及普通属性(例如left,right,height,width等等)的trans ...
- zepto源码研究 - zepto.js (zepto.init)
简要:当我们用$()时,便会直接调用zepto.init 生成zepto对象,那zepto.init是如何根据不同类型的参数来生产指定对象呢? zepto.init = function(select ...
- zepto源码研究 - zepto.js - 6(模板方法)
width height 模板方法 读写width/height ['width', 'height'].forEach(function(dimension){ //将width,hegih ...
- zepto源码研究 - ajax.js($.ajax具体流程分析)
简要:$.ajax是zepto发送请求的核心方法,$.get,$.post,$.jsonp都是封装了$.ajax方法.$.ajax将jsonp与异步请求的代码格式统一起来,内部主要是先处理url,数据 ...
- zepto源码研究 - ajax.js($.ajaxJSONP 的分析)
简要:jsonp是一种服务器和客户端信息传递方式,一般是利用script元素赋值src来发起请求.一般凡是带有src属性的元素发起的请求都是可以跨域的. 那么jsonp是如何获取服务器的数据的呢? j ...
- zepto源码研究 - ajax.js(请求过程中的各个事件分析)
简要:ajax请求具有能够触发各类事件的功能,包括:触发全局事件,请求发送前事件,请求开始事件,请求结束事件等等,贯穿整个ajax请求过程,这是非常有用的,我们可以利用这些事件来做一些非常有意思的事情 ...
随机推荐
- python 深拷贝和浅拷贝浅析
简单点说 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.id会变化2. copy.deepcopy 深拷贝 拷贝对象及其子对象.id会变化 >>> im ...
- 使用cglib动态创建java类
转至:http://ckwang17.iteye.com/blog/963881 cglib 是一个开源项目! 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Jav ...
- poj 2195Going Home
http://poj.org/problem?id=2195 #include<cstdio> #include<cstring> #include<cmath> ...
- poj 2031Building a Space Station
http://poj.org/problem?id=2031 #include<cstdio> #include<cstring> #include<cmath> ...
- Callback函数详解(我感觉,回掉函数的本质是函数指针,在业务做循环处理的时候,调用一下通知外部)
2010年的最后一天了,转载一篇自己认为还不错的文章与大家分享.希望对大家有所帮助. 一,回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度 ...
- Signing key has not been configured
Signing key has not been configured.https://dev.openwrt.org/changeset/38284 Add package signing key ...
- 【数学】HDU 5761 Rower Bo
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5761 题目大意: 船在(0,a),船速v1,水速v2沿x轴正向,船头始终指向(0,0),问到达(0, ...
- HDOJ 2200 Eddy's AC难题(数学组合概率题)
Problem Description Eddy是个ACMer,他不仅喜欢做ACM题,而且对于Ranklist中每个人的ac数量也有一定的研究,他在无聊时经常在纸上把Ranklist上每个人的ac题目 ...
- TCP协议下Socket的基础编程类型
套接字的基本操作有: 创建(socket).命名(bind).侦听(listen).连接(accept).关闭(shutdown).发送(send).接受(recv). 下面逐个分析: 一.创建(so ...
- 使用Windows驱动的虚拟打印机,打印Excel表格无表格线问题解决(2)
测试: 经前天的测试,最终还是没有明显的定夺到底是驱动的问题,还是打印机的问题.但是按照可能性来排查,最明显的一点就是其他测试环境不变的情况下增加一张图片,就可以打印出表格线,我始终觉得这里是突破点, ...