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属性管理)的更多相关文章

  1. zepto源码研究 - zepto.js - 1

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

  2. zepto源码研究 - fx_methods.js

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

  3. zepto源码研究 - deferred.js(jquery-deferred.js)

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

  4. zepto源码研究 - fx.js

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

  5. zepto源码研究 - zepto.js (zepto.init)

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

  6. zepto源码研究 - zepto.js - 6(模板方法)

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

  7. zepto源码研究 - ajax.js($.ajax具体流程分析)

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

  8. zepto源码研究 - ajax.js($.ajaxJSONP 的分析)

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

  9. zepto源码研究 - ajax.js(请求过程中的各个事件分析)

    简要:ajax请求具有能够触发各类事件的功能,包括:触发全局事件,请求发送前事件,请求开始事件,请求结束事件等等,贯穿整个ajax请求过程,这是非常有用的,我们可以利用这些事件来做一些非常有意思的事情 ...

随机推荐

  1. 前端自动化之babel本地化安装

    npm添加package.json cd到项目根目录直接调用npm init 会创建package.json文件 本地安装bebel(并非全局安装,这种情况下cmd命令中babel命令不识别): 步骤 ...

  2. 转:为什么要使用NoSQL

    为什么要使用NoSQL NoSQL在2010年风生水起,大大小小的Web站点在追求高性能高可靠性方面,不由自主都选择了NoSQL技术作为优先考虑的方面.今年伊始,InfoQ中文站有幸邀请到凤凰网的孙立 ...

  3. 【Oracle】windows默认共享的打开和关闭?

    Windows启动时都会默认打开admin$ ipc$ 和每个盘符的共享,对于不必要的默认共享,一般都会把它取消掉,可当又需要打开此默认共享时,又该从哪里设置呢,一般来说有两个地方,MSDOS命令和计 ...

  4. css+div 布局遇到的小常识

    /根目录../上层目录举例如下: 在photo.css文件中写入: div.ls{ background:url(../photo/framels.jpg) no-repeat left; }div. ...

  5. 引用 运行asp.net程序时候,编译器错误消息: CS0016: 未能写入输出文件“c:\WINDOWS\Microsoft.NET\Fra

    引用 运行asp.net程序时候,编译器错误消息: CS0016: 未能写入输出文件“c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary A ...

  6. C# 将数据集以excel的形式输出

    private void SaveLastMonthAuthorPays()        {            string fileName = "LastMonthAuthorPa ...

  7. Topcoder 好题推荐

    SRM SRM147 DIV1 1000pt DP SRM148 DIV1 1100pt 递归 SRM149 DIV1 1000pt math SRM150 DIV1 500pt DP SRM469 ...

  8. Jenkins 初见

    在网上貌似没有找到Jenkins的中文的太多的文档,有的都是关于Hudson的一些 零零散散的,所以自己边学习边实践总结了以下系列文章,希望有助于大家对于Jenkins的使用. 本系列文章是基于我3年 ...

  9. linux —— 问题解决(锦集)

    这里收录了我在使用ubuntu 时遇到的问题以及解决方案. 1. Ubuntu上由于/boot容量不足引起的无法更新系统 解决: [ link1 ] [ link2 ] 2. 在未联网的情况下,sud ...

  10. php-redis扩展模块安装记录

    redis的安装可以参考:centos下部署redis服务环境的操作记录 下面记录下php-redis扩展模块的安装过程:php的安装目录是/Data/app/php5.6.26 下载phpredis ...