index:

  1. $.fn = {
    ......
  2.  
  3. indexOf: emptyArray.indexOf,
    }
  1. index: function(element){
  2. //这里的$(element)[0]是为了将字符串转成node,因为this是个包含node的数组
  3. //当不指定element时,取集合中第一条记录在其父节点的位置
  4. //this.parent().children().indexOf(this[0])这句很巧妙,和取第一记录的parent().children().indexOf(this)相同
  5. return element ? this.indexOf($(element)[]) : this.parent().children().indexOf(this[])
  6. },

obj.index(element) : 如果element有,则obj作为一个数组,取element在这个obj中的索引。如果element没有,则此函数的意思是取dom节点所在父类中的索引。

  1. <div id="first" class="test">
  2. <div id="second" class="test">
  3. </div>
  4. </div>
  5.  
  6. 测试:
  7.  
  8. $(".test").index($("#second"));
  9.  
  10. $(".test").index($("#second")[]);
  11.  
  12. $(".second").index();
  13. -
  14. $("#second").index();

hasClass:

  1. /**
  2. * 是否含有指定的类样式
  3. * @param name
  4. * @returns {boolean}
  5. */
  6. hasClass: function(name){
  7. if (!name) return false
  8. //some ES5的新方法 有一个匹配,即返回true 。
  9. return emptyArray.some.call(this, function(el){
  10. //this是classRE(name)生成的正则
  11. return this.test(className(el))
  12. }, classRE(name))
  13. },

array.some(function(curentValue,index,arr){},thisValue),thisValue作为回调函数中的this,若没有指定thisValue,则回调函数中的this为undefined,

className(el) :一般取el.className(svg除外),classRE(name) 生成一个name的正则表达式,

  1. testRegExp的方法,参数是字符串,返回值是boolean类型。
    matchString的方法,参数是正则表达式,返回值是数组。

classRE:

  1. /**
  2. * 将参数变为正则表达式
  3. * @param name
  4. * @returns {*}
  5. */
  6. function classRE(name) {
  7. //classCache,缓存正则
  8. //TODO 缓存可以理解,但应该在重复使用第二次时再缓存吧,直接缓存?
  9. return name in classCache ?
  10. classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
  11. }

className:

  1. /**
  2. * 对SVGAnimatedString的兼容?
  3. * @param node
  4. * @param value
  5. * @returns {*}
  6. */
  7. function className(node, value){
  8. var klass = node.className || '',
  9. svg = klass && klass.baseVal !== undefined
  10.  
  11. if (value === undefined) return svg ? klass.baseVal : klass
  12. svg ? (klass.baseVal = value) : (node.className = value) //class设值
  13. }

addClass:

  1. /**
  2. * 增加一个或多个类名
  3. * @param name 类名/空格分隔的类名/函数
  4. * @returns {*}
  5. */
  6. addClass: function(name){
  7. if (!name) return this
  8.  
  9. //遍历增加
  10. return this.each(function(idx){
  11. //已存在,返回
  12. if (!('className' in this)) return
  13. classList = []
  14. var cls = className(this), newName = funcArg(this, name, idx, cls) //修正类名,处理name是函数,SVG动画兼容的情况
  15.  
  16. //多个类,空格分隔为数组
  17. newName.split(/\s+/g).forEach(function(klass){
  18. if (!$(this).hasClass(klass)) classList.push(klass)
  19. }, this)
  20.  
  21. //设值 如果所有的都是重复的,就不会执行
  22. classList.length && className(this, cls + (cls ? " " : "") + classList.join(" "))
  23. })
  24. },

addClass(name)的name参数可以为函数,newName.split(/\s+/g) :根据空格分为数组,这是一个技巧,这里是先对newName过滤,把重复的class去掉,

然后以字符串的形式连接原来的className并赋值给dom

removeClass:

  1. /**
  2. *删除一个或多个类名 同addClass
  3. * 原理: className.repalce 替换撒谎年初
  4. * @param name 类名/空格分隔的类名/函数
  5. * @returns {*}
  6. */
  7. removeClass: function(name){
  8. return this.each(function(idx){
  9. if (!('className' in this)) return
  10. if (name === undefined) return className(this, '')
  11. classList = className(this)
  12. funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){
  13. //替换删除
  14. classList = classList.replace(classRE(klass), " ")
  15. })
  16. className(this, classList.trim())
  17. })
  18. },

这里要删除一个字符串里面的指定的子字符串,可以使用replace(classRE," ")

toggleClass:

  1. /**
  2. * 切换类的添加或移除
  3. * 原理 如果存在,即removeClass移除,不存在,即addClass添加
  4. * @param name 类名/空格分隔的类名/函数
  5. * @param when
  6. * @returns {*}
  7. */
  8. toggleClass: function(name, when){
  9. if (!name) return this
  10. return this.each(function(idx){
  11. var $this = $(this), names = funcArg(this, name, idx, className(this))
  12. names.split(/\s+/g).forEach(function(klass){
          // 这里的when可以作为标记,来判断是add还是remove
  13. (when === undefined ? !$this.hasClass(klass) : when) ?
  14. $this.addClass(klass) : $this.removeClass(klass)
  15. })
  16. })
  17. },

attr:

  1. /**
  2. * 设置属性
  3. * @param node
  4. * @param name
  5. * @param value
  6. */
  7. function setAttribute(node, name, value) {
  8. //value为null/undefined,处理成删除,否则设值
  9. value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
  10. }
  11.  
  12. /**
  13. * 元素的HTML属性读写
  14. * 读:原理是getAttribute
  15. * 写:原理是setAttribute
  16. * @param name
  17. * @param value
  18. * @returns {undefined}
  19. */
  20. attr: function(name, value){
  21. var result;
  22. //仅有name,且为字符串时,表示读
  23. return (typeof name == 'string' && !( in arguments)) ?
  24. //$是空的 或里面的元素非元素,返回undefined
  25. (!this.length || this[].nodeType !== ? undefined :
  26. //直接用getAttribute(name)读,
  27. (!(result = this[].getAttribute(name)) && name in this[]) ? this[][name] : result
  28. ) : //否则是写,不管name为对象{k:v},或name value 都存在
  29. this.each(function(idx){
  30. if (this.nodeType !== ) return //非元素
  31. //如果name为对象,批量设置属性
  32. if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
  33. //处理value为函数/null/undefined的情况
  34. else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
  35. })
  36. },

经整理后如下:

  1. //如果只有一个参数,且name为string类型,则此函数为读模式
  2. if((typeof name == 'string' && !( in arguments)) ){
  3. if(!this.length || this[].nodeType !== ) return undefined;
  4.  
  5. if((result = this[].getAttribute(name))){
  6. // 如果dom有这个属性,则返回
  7. return result;
  8. }else{
  9. // 如果dom没有这个属性,则从内存中获取并返回
  10. if(name in this[]) return this[][name];
  11. }
  12. }else{
  13. this.each(function(idx){
  14. if (this.nodeType !== ) return //非元素
  15. //如果name为对象,批量设置属性
  16. if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
  17. //处理value为函数/null/undefined的情况,这里的funcArg函数在整个zepto中复用了很多次,
  18. // 考虑参数为函数的情况在很大方法中出现,setAttribute处理value为null的情况,实际就是removeAttribute
  19. else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
  20. })
  21. }

data:

  1. /**
  2. * 设置自定义数据
  3. * 注意与jQuery的区别,jQuery可以读写任何数据类型。这里原理是H5的data-,或直接setAttribute/getAttribute,只能读写字符串
  4. * @param name
  5. * @param value
  6. * @returns {*}
  7. */
  8. /*getAttribute/setAttribute可以操作所有的dataset内容,dataset内容只是attribute的一个子集,
  9. 特殊就特殊在命名上了。那么为什么我们还要用data-*呢,
  10. 一个最大的好处是我们可以把所有自定义属性在dataset对象中统一管理,遍历啊神马的都哦很方便,
  11. 而不至于零零散散了,所以用用还是不错的。*/
  12. data: function(name, value){
  13. var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
  14.  
  15. var data = ( in arguments) ?
  16. this.attr(attrName, value) :
  17. this.attr(attrName)
  18.  
  19. return data !== null ? deserializeValue(data) : undefined
  20. },

函数中的第一步是将驼峰命名的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,例子如下:

  1. function data(name, value){
  2. var attrName = name.replace(capitalRE, '-$1').toLowerCase();
  3. if(isObject(value)) value = JSON.stringify(value);
  4. if(this[0].dataset){
  5. var data = (1 in arguments) ?
  6. this[0].dataset[attrName] = value :
  7. this[0].dataset[attrName];
  8. }else{
  9. attrName = 'data-'+attrName;
  10. var data = (1 in arguments) ?
  11. this.attr(attrName, value) :
  12. this.attr(attrName)
  13. }
  14.  
  15. return data !== null ? deserializeValue(data) : undefined
  16. }

val:

  1. /**
  2. * 适合表单元素读写
  3. * 写: 写入每个元素 element.value
  4. * 读: 读第一个元素
  5. * @param value 值/函数
  6. * @returns {*}
  7. */
  8. val: function(value){
  9. return 0 in arguments ?
  10. //只有一个参数是写,
  11. this.each(function(idx){
  12. this.value = funcArg(this, value, idx, this.value)
  13. }) :
  14. //如果是读
  15. (this[0] && (this[0].multiple ? //对多选的select的兼容处理,返回一个包含被选中的option的值的数组
  16. $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :
  17. this[0].value)
  18. )
  19. },

这里的this[0].multiple 可以判断是否为多选的select,select节点的value属性与被选中的option的value属性是相关联的。如下例子

  1. select#third选中的option的value为1
  2. console.log($("#third")[0].value);
  3. 结果:1
  4.  
  5. console.log($("#third")[0].value = 2);
  6. select#third选中的option的value变为2
  7. 结果:2
  1.  
  1.  
  1.  

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. LayerDrawable 资源

    与 StateListDrawable 有点类似,LayerDrawable 也可包含一个 Drawable 数组,因此系统 将会按这些 Drawable 对象的数组顺序来绘制它们,索引最大的 Dra ...

  2. onCreateOptionsMenu与onCreateContextMenu差别

    onCreateOptionsMenu只会在启动时调用一次,而onCreateContextMenu则每次都会调用,这是因为onCreateContextMenu需要为所有的View控件的上下文菜单服 ...

  3. 配置Session变量的生命周期

    在Web.config文件中配置Session变量的生命周期是在<sessionState></sessionState>节中完成的,在配置Session的生命周期时,可以设置 ...

  4. 关于兄弟QWidget间的位置重叠

    转自:http://hi.baidu.com/dbzhang800/item/a7bf1f1e983c6af964eabf45?qq-pf-to=pcqq.group 缘起 csdn上一用户抱怨:她的 ...

  5. linux shell 终端中文乱码(转)

    方法一:修改/etc/sysconfig/i18n 文件把里面的LANG="en_US"改成 GB2312就可以了要重启一下机器不用重启的方法,直接# LANG="GB2 ...

  6. DataGridView DataGridViewCheckBoxColumn编辑时实时触发事件

    正常响应CellValueChanged()事件时,当改变checkbox状态时,只有当焦点离开该单元格时才能触发CellValueChanged()事件, 如果要改变checkbox值时实时触发Ce ...

  7. Posix-linux_route

      route命令显示或者修改本地IP路由表.   语法:   [plain] route [-CFvnee]   route  [-v]  [-A family]  add [-net|-host] ...

  8. NSString去掉火车和空格

    //    backString = [backString stringByReplacingOccurrencesOfString:@"\r" withString:@&quo ...

  9. 高性能MySql进化论(一):数据类型的优化_上

    在数据库的性能调优的过程中会涉及到很多的知识,包括字段的属性设置是否合适,索引的建立是否恰当,表结构涉及是否合理,数据库/操作系统 的设置是否正确…..其中每个topic可能都是一个领域. 在我看来, ...

  10. 获取CPU使用情况信息(转)

    获取了内存使用情况,也可以使用PHP的 getrusage()获取CPU使用情况,该方法在windows下不可用.    print_r(getrusage()); /* 输出 Array ( [ru ...