jQuery属性操作
jQuery 的属性操作的核心部分其实就是对底层 getAttribute()、setAttributes()等方法的一系列兼容性处理
...
if ( notxml ) {
name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
} if ( value !== undefined ) { if ( value === null ) {
jQuery.removeAttr( elem, name );
return; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret; } else {
elem.setAttribute( name, value + "" );
return value;
} } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined
return ret === null ?
undefined :
ret;
}
...
在方法的内部会用一系列的钩子(HOOKS)来把需要处理的情况约定好,如 attrHooks 等,钩子的结构都大致类似
var someHook = {
get: function(elem) {
// obtain and return a value
return "something";
},
set: function(elem, value) {
// do something with value
}
}
最后通过 access 方法来修正传入的参数使 get、set 一体化,然后暴露给外部 API
关于 access 的内容会在下期中进行介绍
jQuery.fn.extend( {
attr: function( name, value ) {
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
return this.each( function() {
jQuery.removeAttr( this, name );
} );
},
prop: function( name, value ) {
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
},
...
jQuery.attr: function( elem, name, value, pass )
前三个参数不需要多说,最后一个参数 pass 是用来判断在 HTML 属性与 jQuery 方法同名时是否调用同名的 jQuery 方法的
if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
return jQuery( elem )[ name ]( value );
}
如果 getAttribute 方法挂了,就转用 prop 方法
// Fallback to prop when attributes are not supported
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
attrHooks专门处理一些特殊的属性
在它定义的地方定义了对 type 和 value 的处理
- type: jQuery.support.radioValue 为 false 时,在设置 input 的 type 为 radio的时候要先把 value 备份一份,然后再写回去
attrHooks: {
type: {
set: function( elem, value ) {
if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
// Setting the type on a radio button after the value resets the value in IE6-9
// Reset value to default in case type is set after value during creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
}
},
- value:jQuery 把 value 的 set 和 get 都交给了nodeHook 来处理,这里解决的是 IE6/7的 button 元素的 DOM 属性 value
value: {
get: function( elem, name ) {
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
return nodeHook.get( elem, name );
}
return name in elem ?
elem.value :
null;
},
set: function( elem, value, name ) {
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
return nodeHook.set( elem, value, name );
}
// Does not return so that setAttribute is also used
elem.value = value;
}
}
- 在代码的后面仍然有几个 attrHooks 的处理情况,是通过属性的方式挂载到了 attrHooks 上面,有兴趣的童鞋可以参考 jQuery.support 一章关于这里的说明
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each( [ "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
} );
} ); // Set contenteditable to false on removals(#10429)
// Setting to empty string throws an error as an invalid value
jQuery.attrHooks.contenteditable = {
get: nodeHook.get,
set: function( elem, value, name ) {
if ( value === "" ) {
value = "false";
}
nodeHook.set( elem, value, name );
}
};
} // Some attributes require a special call on IE
if ( !jQuery.support.hrefNormalized ) {
jQuery.each( [ "href", "src", "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
get: function( elem ) {
var ret = elem.getAttribute( name, 2 );
return ret === null ? undefined : ret;
}
} );
} );
} if ( !jQuery.support.style ) {
jQuery.attrHooks.style = {
get: function( elem ) {
// Return undefined in the case of empty string
// Normalize to lowercase since IE uppercases css property names
return elem.style.cssText.toLowerCase() || undefined;
},
set: function( elem, value ) {
return ( elem.style.cssText = value + "" );
}
};
}
boolHook 专门处理如下布尔型的 HTML 属性
bool: /^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i
内部具体实现逻辑比较简单就不多说了,需要注意的一点是在 get 的时候,jQuery 用的是 prop 方法来取得的值
property = jQuery.prop( elem, name );
nodeHook 专门用来处理 IE6/7这两个傻X的 get/setAttribute 的问题,这里采用属性节点来直接设置和读取元素属性值
// IE6/7 do not support getting/setting some attributes with get/setAttribute
if ( !getSetAttribute ) { //这三个属性如果为空,则需要返回 undefined
fixSpecified = {
name: true,
id: true,
coords: true
}; // Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = jQuery.valHooks.button = {
get: function( elem, name ) {
var ret;
ret = elem.getAttributeNode( name );
return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
ret.value :
undefined;
},
set: function( elem, value, name ) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
if ( !ret ) {
ret = document.createAttribute( name );
elem.setAttributeNode( ret );
}
return ( ret.value = value + "" );
}
};
hook 约定完成以后,开始正式处理元素属性的设置、删除和读取,判断的逻辑主要围绕 value 的值
if ( value !== undefined ) {//注意这里是全等,所以 null 在这里是不行的( null == undefined )
if ( value === null ) {//这种方式可以把值删掉
jQuery.removeAttr( elem, name );
return;
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {//这里直接进行了赋值操作
return ret;
} else {
elem.setAttribute( name, value + "" );
return value;
}
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {//同样,这里直接进行了取值操作
return ret;
} else {
ret = elem.getAttribute( name );//都不需要特殊处理,就直接调用原始的方法
// Non-existent attributes return null, we normalize to undefined
// 这里统一把不存在的属性值处理成了 undefined
return ret === null ?
undefined :
ret;
}
jQuery.removeAttr: function( elem, value )
这个方法支持空格分隔的属性名称,所以一次可以移除多个属性
attrNames = value.split( core_rspace );
这个方法主要做了三个事情:
- 移除前把属性的值置空,用来解决 Webkit 内核浏览器不能移除 HTML 属性 style 的问题
// See #9699 for explanation of this approach (setting first, then removal)
// Do not do this for boolean attributes (see #10870)
if ( !isBool ) {
jQuery.attr( elem, name, "" );
}
- get/setAttribute 方法不支持时,会把 HTML 属性对应的 DOM 属性传入进去
//DOM属性必须是驼峰的
propName = jQuery.propFix[ name ] || name;
...
elem.removeAttribute( getSetAttribute ? name : propName );
...
propFix: {
tabindex: "tabIndex",
readonly: "readOnly",
"for": "htmlFor",
"class": "className",
maxlength: "maxLength",
cellspacing: "cellSpacing",
cellpadding: "cellPadding",
rowspan: "rowSpan",
colspan: "colSpan",
usemap: "useMap",
frameborder: "frameBorder",
contenteditable: "contentEditable"
}
布尔类型的 HTML 属性,需要同步设置对应的 DOM 属性为 false
// Set corresponding property to false for boolean attributes
if ( isBool && propName in elem ) {
elem[ propName ] = false;
}
jQuery.prop: function( elem, name, value )
prop方法的处理过程与attr方法大同小异,最大的不同表现在一些hooks的处理上,具体实现不在赘述
propHooks原始定义
propHooks: {
tabIndex: {
get: function( elem ) {
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
var attributeNode = elem.getAttributeNode("tabindex");
return attributeNode && attributeNode.specified ?
parseInt( attributeNode.value, 10 ) :
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
0 :
undefined;
}
}
}
propHooks的一些扩展
// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
get: function( elem ) {
var parent = elem.parentNode; if ( parent ) {
parent.selectedIndex; // Make sure that it also works with optgroups, see #5701
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
return null;
}
});
}
.removeProp: function( name )
prop属性的删除方法比较简单,所以jQuery没有对它再进行一层封装
removeProp: function( name ) {
//进行名称上的一些修正
name = jQuery.propFix[ name ] || name;
return this.each(function() {
// try/catch handles cases where IE balks (such as removing a property on window)
try {
//注意采用的删除方式
this[ name ] = undefined;
delete this[ name ];
} catch( e ) {}
});
},
.addClass: function( value )
addClass: function( value ) {
var classNames, i, l, elem,
setClass, c, cl;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
//jQuery1.4开始,这个方法开始可以接受一个函数作为参数
//函数中的this被指向了当前的这个dom元素
//并且接收元素在当前set中的序号和原始的class名称作为参数
jQuery( this ).addClass( value.call(this, j, this.className) );
});
}
if ( value && typeof value === "string" ) {
//空格分离的类名
classNames = value.split( core_rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
//只接受元素节点
if ( elem.nodeType === 1 ) {
//最简单的情况,元素还没有任何类名
//这种情况就不在进行for循环了
//从这一句简单的代码也可以看出jQuery的一个很重要的代码风格,就是从来不做多余的事情
//判断长度是为了避免重复的类名
//这里和后面可以看出对元素类名的赋值使用的都是className属性
if ( !elem.className && classNames.length === 1 ) {
elem.className = value;
} else {
//不是最简单的情况
//首先把现有的类名用约定的格式封装起来,作为拼接结果的第一项
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
//避免添加重复的类名进去
if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
setClass += classNames[ c ] + " ";
}
}
//剔除首尾空格
elem.className = jQuery.trim( setClass );
}
}
}
}
//保证可以进行链式调用
return this;
},
.removeClass: function( value )
这个方法基本就是addClass方法的逆过程,不同的是,这个方法我们如果什么参数都不传,它会把所有的类名都删除掉
jQuery官方的说明
If a class name is included as a parameter, then only that class will be removed from the set of matched elements. If no class names are specified in the parameter, all classes will be removed.
相关的代码片段
...
if ( (value && typeof value === "string") || value === undefined ) {
...
elem.className = value ? jQuery.trim( className ) : "";
...
.toggleClass: function( value, stateVal )
这是一个稍微有点复杂的方法,先看官网对它最新的说明

基本用法、接受的参数等与addClass等方法基本类似,最大的不同在于多出来的state参数,用于手动控制元素类名的增删
另外,在官方的文档中,有一段话是值得关注的:
As of jQuery 1.4, if no arguments are passed to .toggleClass(), all class names on the element the first time .toggleClass() is called will be toggled. Also as of jQuery 1.4, the class name to be toggled can be determined by passing in a function.
意思是这个方法同样可以什么参数都不传,它的作用在当前元素第一次调用的时候类似于removeClass方法,会把现存的所有类名清空,那么如果再链式调用一次这个方法呢?
toggleClass: function( value, stateVal ) {
var type = typeof value,
isBool = typeof stateVal === "boolean";
if ( jQuery.isFunction( value ) ) {
return this.each(function( i ) {
//传入函数的用法,这里把stateVal参数也传了进去
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
});
}
return this.each(function() {
if ( type === "string" ) {
// toggle individual class names
var className,
i = 0,
self = jQuery( this ),
state = stateVal,
classNames = value.split( core_rspace );
//又是一种巧妙的用法,集合自增循环、赋值、判断于一句话
while ( (className = classNames[ i++ ]) ) {
// check each className given, space separated list
// 状态参数的优先级高于hasClass
state = isBool ? state : !self.hasClass( className );
self[ state ? "addClass" : "removeClass" ]( className );
}
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) {
// store className if set
// 这里把原始的类名缓存了起来
jQuery._data( this, "__className__", this.className );
}
// toggle whole className
// 最特么烦jQuery这种写法,多写几个if会死啊!!
/* 分解一下,大概可以分为以下这么几种情况
* 1、如果this.className存在,总是置空,不受switch值的影响
* 2、如果this.className不存在,switch为false时类名保持不变(置空),为true或undefined时为jQuery._data( this, "__className__" ) || ""
*/
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
所以链式零参数的调用时,会把元素的类名恢复回来.
.hasClass: function( selector )
用法不多说,有一点需要注意的是,hasClass方法在检测类名时,是把传入的selector作为一个整体来检测的,并没有按照空格分离的操作,这一点需要注意
相关的代码片段
var className = " " + selector + " ",
.val: function( value )
这个方法与上面的这些方法大同小异,有一点我不太明白的是这个方法为什么没有接入 access 方法呢?
jQuery属性操作的更多相关文章
- jquery——属性操作、特殊效果
1. attr().prop() 取出或者设置某个属性的值 <!DOCTYPE html> <html lang="en"> <head> &l ...
- jQuery源代码学习之八——jQuery属性操作模块
一.jQuery属性模块整体介绍 jQuery的属性操作模块分四个部分:html属性操作,dom属性操作,类样式操作,和值操作. html属性操作(setAttribute/getAttribute) ...
- jQuery 属性操作和CSS 操作
如有在jQuery方法中涉及到函数,此函数必定会返回一个数值(函数由于运行次数不同触发一些不同效果) jQuery 属性操作方法(以下方法前些日子学习过,不再赘述) addClass() attr() ...
- python全栈开发day48-jqurey自定义动画,jQuery属性操作,jQuery的文档操作,jQuery中的ajax
一.昨日内容回顾 1.jQuery初识 1).使用jQuery而非JS的六大理由 2).jQuery对象和js对象转换 3).jQuery的两大特点 4).jQuery的入口函数三大写法 5).jQu ...
- jQuery属性操作(四)
通过阅读jQuery为属性操作封装的基本方法和为处理兼容性问题提供的hooks,发现jQuery在属性操作方面并没有做过多的设计,只是处理一下兼容性问题,然后调用基础的DOM操作方法.以下是对JQue ...
- jQuery属性操作(二)
挂载到$上的几个属性操作方法分析,发现属性操作用到了sizzle封装的方法 attr: function( elem, name, value ) { var hooks, ret, ...
- jQuery属性操作(一)
下载了jQuery的UI组件,发现内容还挺多的,还是决定先把jQuery的源码看完一遍之后再涉足UI组件.考虑到队列和动画使用较少,特别是动画,基本开始使用css3完成.因此暂时略过,开始看jQuer ...
- web前端----jQuery属性操作
知识点总结 1.属性 属性(如果你的选择器选出了多个对象,那么默认只会返回出第一个属性). attr(属性名|属性值) - 一个参数是获取属性的值,两个参数是设置属性值 - 点击加载图片示例 remo ...
- Jquery属性操作(入门二)
********JQuery属性相关的操作******** 1.属性 属性(如果你的选择器选出了多个对象,那么默认只会返回出第一个属性). attr(属性名|属性值) - 一个参数是获取属性的值,两个 ...
随机推荐
- Android四大组件之actiivity
1.Acitivity Activity是Android一个非常重要的用户接口(四大组件之一),是可见的,主要是用户和应用程序之间进行交互的接口.在每个Activity中都可以放很多控件,所以也可以把 ...
- Jackson
Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 1. 下载依赖库jar包 Jackson的jar all下载地址:http:// ...
- Java Service Wrapper简介与使用
在实际开发过程中很多模块需要独立运行,他们并不会以web形式发布,传统的做法是将其压缩为jar包独立运行,这种形式简单易行也比较利于维护,但是一旦服务器重启或出现异常时,程序往往无法自行修复或重启.解 ...
- C#_技巧:窗口抖动
原理 * 窗口抖动:即每隔一段很小的时间,窗口位置发生变化 * 时间控制:利用for循环||利用timer * 窗口位置发生变化:控件Left/Top属性或Location属性, 注:Left/To ...
- MySQL优化性能my.cnf详解
提供一个MySQL 5.6版本适合在1GB内存VPS上的my.cnf配置文件(点击这里下载文件): [client] port=3306 socket=/tmp/mysql.sock [mysqld] ...
- PHP 水印设置
一.图片水印 <?php /* 覆盖水印 */ $image = ImageCreateFromJPEG('memcached.jpg'); $stamp = ImageCreateFromPN ...
- Java多线程之this与Thread.currentThread()的区别——java多线程编程核心技术
package mythread; public class CountOperate extends Thread{ public CountOperate(){ System.out.prin ...
- SQL TOP 子句、SQL LIKE 操作符、SQL 通配符
TOP 子句 TOP 子句用于规定要返回的记录的数目. 对于拥有数千条记录的大型表来说,TOP 子句是非常有用的. 注释:并非所有的数据库系统都支持 TOP 子句. SQL Server 的语法: S ...
- 给Source Insight做个外挂系列之六--“TabSiPlus”的其它问题
关于如何做一个Source Insight外挂插件的全过程都已经写完了,这么一点东西拖了一年的时间才写完,足以说明我是一个很懒的人,如果不是很多朋友的关心和督促,恐怕是难以完成了.许多朋友希望顺着本文 ...
- 关于MVC4.0中@Styles.Render用法与详解
本文分享于http://keleyi.com/a/bjac/q74dybjc.htm文章,感觉写的蛮好所以就拿过来做笔记了,希望对大家有帮助 最近公司的新项目用了MVC 4.0,接下来一步步把 工作中 ...