当前位置: 首页 > 编程日记 > 正文

jQuery源码分析系列:属性操作

属性操作

1.6.1相对1.5.x最大的改进,莫过于对属性.attr()的重写了。在1.6.1中,将.attr()一分为二: .attr()、.prop(),这是一个令人困惑的变更,也是一个破坏性的升级,会直接影响到无数的网站和项目升级到1.6。

简单的说,.attr()是通过setAttribute、getAttribute实现,.prop()则通过Element[ name ]实现:

jQuery.attr

setAttribute, getAttribute

jQuery.removeAttr

removeAttribute, removeAttributeNode(getAttributeNode )

jQuery.prop

Element[ name ]

jQuery.removeProp

delete Element[ name ]

事实上.attr()和.prop()的不同,是HTML属性(HTML attributes)和DOM属性(DOM properties)的不同。HTML属性解析的是HTML代码中的存在的属性,返回的总是字符串,而DOM属性解析的是DOM对象的属性,可能是字符串,也可能是一个对象,可能与HTML属性相同,也可能不同。

1 <a href="abc.html" class="csstest" style="font-size: 30px;">link</a>
2 
3 <input type="text" value="123">
4 
5 <input type="checkbox" checked="checked">

javascript代码:

 1 console.info( $('#a').attr('href') ); // abc.html
 2 
 3 console.info( $('#a').prop('href') ); // file:///H:/open/ws-nuysoft/com.jquery/jquery/abc.html
 4 
 5  
 6 console.info( $('#a').attr('class') ); // csstest
 7 console.info( $('#a').prop('class') ); // csstest
 8 
 9 console.info( document.getElementById('a').getAttribute('class') ); // csstest
10 
11 console.info( document.getElementById('a').className ); // csstest
12 
13 console.info( $('#a').attr('style') ); // font-size: 30px;
14 
15 console.info( $('#a').prop('style') ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...}
16 
17 console.info( document.getElementById('a').getAttribute('style') ); // font-size: 30px;
18 
19 console.info( document.getElementById('a').style ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...}
20 
21 console.info( $('#text').attr('value') ); // 123
22 console.info( $('#text').prop('value') ); // 123
23 
24 console.info( $('#checkbox').attr('checked') ); // checked
25 console.info( $('#checkbox').prop('checked') ); // true
26 
27  

不同之处总结如下:

1.属性名可能不同,尽管大部分的属性名还是相似或一致的。

2.HTML属性值总是返回字符串,DOM属性值则可能是整型、字符串、对象,可以获取更多的内容

3.DOM属性总是返回当前的状态(值),而HTML属性(在大多数浏览)返回的初始化时的状态(值)

4.DOM属性只能返回固定属性名的值,而HTML属性则可以返回在HTML代码中自定义的属性名的值

5.相对于HTML属性的浏览器兼容问题,DOM属性名和属性值在浏览器之间的差异更小,并且DOM属性也有标准可依

优先使用.prop(),因为.prop()总是返回最新的状态(值)

从源码可以看出.attr()的处理过程,先特殊处理各种特殊情况,再用约定getAttribute()和setAttribute()方法

jQuery.attr()源码:

.attr(attributeName) 取得第一个匹配元素的属性值(当属性没有被设置时,返回undefined,不能用在文本节点、注释节点、属性节点上)

.attr(attributeName, value) 设置单个属性

.attr(map) 设置多个属性

.attr(attributeName, function(index, attr)) 通过函数的返回值设置属

 1     //工具方法  设置或获取HTML元素  setAttribute和getAttribute实现        
 2     attr: function( elem, name, value, pass ) {
 3             var nType = elem.nodeType;
 4             //节点类型不能是:文本 注释 属性节点
 5             if(!elem || nType === 3 || nType === 8 nType === 2){
 6                 return undefined;
 7             }
 8             //1>>遇到与方法同名的属性 则执行方法
 9             //2>>遇到扩展或需要修正的属性 执行相应的方法
10             //判断属性名是否在jQuery提供的方法jQuery.attrFn中,是则直接调用方法。
11             if(pass && name in jQuery.attrFn){//属性方法
12                 return jQuery(elem)[name](value);
13             }
14             //如果不支持getAttribute 则调用$.prop()方法
15             if(!("getAttribute" in elem)){
16                 return jQuery.prop(elem,name,value);
17             }
18             var ret,hooks,
19                 notxml = nType !==1 || !jQuery.isXMLDoc(elem);//判断documentElement是否存在
20 
21             //格式化name      attrFix: { tabindex: "tabIndex"}
22             name = notxml && jQuery.attrFix[name] || name;
23             //属性钩子:type:  tabIndex
24             hooks = jQuery.attrHooks[name];
25             //如果没有name对应的钩子
26             if(!hooks){
27                 //使用boolean钩子处理boolean属性
28                 (typeof value === "boolean" || value === undefined || value.tolowerCase() === name.toLowerCase())){
29                     //使用布尔钩子(静态方法对象):set get
30                     hooks = boolHook;
31                 //使用表单钩子
32                 }else if (formHook && (jQuery.nodeName(elem,"form") || rinvalidChar.test(name))){
33                 //使用表单钩子(静态方法对象):set get
34                 hooks = formHook;
35                 }
36             }
37 
38             //定义了value   设置或删除
39             if(value !== undefined){
40             /*
41                 typeof null === 'object'   true
42                 typeof undefined === 'undefined'  true
43                 null == undefined   true
44                 null === undefined  false
45             */
46                 if(value === null){//有值但是为空 即将值设置为空
47                     jQuery.reomveAttr(elem,name);
48                     return undefined;
49                 //属性钩子 布尔钩子 表单钩子 如果有对象的钩子 就调用set方法
50                 }else if(hooks && "set" in hooks && noxml && (ret = hooks.set(elem,value,name))!==undefeind){
51                     return ret;
52                 }else{
53                     //调用setAttribute方法
54                     elem.setAttribute(name,"" + value);
55                     return value;
56                 }
57             //value是undefined,说明去属性 ,存在对应钩子有get方法,调用钩子的get方法
58             }else if(hooks && "get" in hooks && notxml){
59                 return hooks.get(elem,name);
60             }else{
61                 //取属性值
62                 ret = elem.getAttribute(name);
63                 //属性不存返回null  格式化为undefined
64                 return ret === null ? undefined : ret;
65             }
66         },

其中调用的钩子有些不明白的地方:

attrHooks源码:如果name = type属性,则加判断后调用setAttribute设置属性值,或者name = tabIndex时通过getAttributeNode("tabIndex")获得//获得自定义对象属性.

    //属性钩子 name = type || tabIndex
    attrHooks: {type: {set: function( elem, value ) {//type属性在IE下不能改变 如果改变报错if ( rtype.test( elem.nodeName ) && elem.parentNode ) {jQuery.error( "type property can't be changed" );} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {var val = elem.value;elem.setAttribute( "type", value );//最后调用setAttribute设置type属性的值if ( val ) {elem.value = val;}return value;}}},tabIndex: {get: function( elem ) {//获得tabIndex的值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;}}},

AttrFn源码:如果name在这个属性方法的对象中,直接调用这个属性方法。

      //取属性用到的方法
      attrFn: {val: true,css: true,html: true,text: true,data: true,width: true,height: true,offset: true},

boolHook源码:

 1     //bool钩子
 2     boolHook = {
 3         get: function( elem, name ) {
 4             // Align boolean attributes with corresponding properties
 5             return elem[ jQuery.propFix[ name ] || name ] ?
 6                 name.toLowerCase() :
 7                 undefined;
 8         },
 9         set: function( elem, value, name ) {
10             var propName;
11             if ( value === false ) {//value不存在时,删除boolean属性
12                 jQuery.removeAttr( elem, name );
13             } else {
14                 //属性名 是否在propFix中,存在就直接调用
15                 propName = jQuery.propFix[ name ] || name;
16                 if ( propName in elem ) {
17                     elem[ propName ] = value;
18                 }
19                 //propName不在elem中就用setAttribute
20                 elem.setAttribute( name, name.toLowerCase() );
21             }
22             return name;
23         }
24     };

formHook源码:设置表单钩子,get/set。

$.prop()源码:

 1         //获取DOM属性
 2         prop: function( elem, name, value ) {
 3             var nType = elem.nodeType;
 4             //节点类型不能是:文本 注释 属性节点
 5             if(!elem || nType === 3 || nType === 8 nType === 2){
 6                 return undefined;
 7             }
 8             var ret,hooks,
 9                 notxml = nType !==1 || !jQuery.isXMLDoc(elem);//判断documentElement是否存在
10 
11             //格式化name      attrFix: { tabindex: "tabIndex"}
12             name = notxml && jQuery.attrFix[name] || name;
13             //属性钩子:name = type || tabIndex
14             hooks = jQuery.attrHooks[name];
15             if(value !== undefined){
16                 //如果钩子存在set  调用set方法
17                 if(hooks && "set" && (ret = hooks.set(elem,value,name))!==undefined){
18                     return ret;
19                 }else{
20                     return (elem[name] = value);
21                 }
22             //读取
23             }else{
24                 if(hooks && "get" && (ret = hooks.get(elem,value,name))!==undefined){
25                     return ret;
26                 }else{
27                     return elem[name];
28                 }
29             }
30         },

jQuery中调用access方法实现jQuery.fn.attr和jQuery.fn.prop:

1   attr: function( name, value ) {
2       return jQuery.access( this, name, value, true, jQuery.attr );
3   },
4 
5   prop: function( name, value ) {
6       return jQuery.access( this, name, value, true, jQuery.prop );
7   }

$.access方法源码:

多功能函数:读取或设置集合的属性值;值为函数时会被执行
  1>>elems:元素的集合,【collection】【类】数组
  2>>key:属性名称,key的只为object时,会拆解key为key,value形式再次执行jQuery.access
  3>>value:属性值
  4>>exec:在属性值为function时是否对设置之前的value值执行函数(这里为true)
  5>>fn:执行的函数
  6>>pass:是否设置为jQuery对象的属性  attr时使用

用于fn:jQuery.fn.css(),jQuery.fn.attr(),jQueyr.fn.prop
  return jQuery.access( this, name, value, true, function( elem, name, value ) {});

说明:主要用于参数的循环处理,为什么要这样做?待详细分析

access:function(elems,key,value,exec,fn,pass){var elems = elems.length;//如果有多个属性就迭代if(typeof key === "object"){for(var k in key){//key的参数循环处理
                        jQuery.access(elems,k,key[k],exec,fn,value);}return elems;}//只设置一个属性if(value !== undefined){exec = !pass && exec && jQuery.isFunction(value);for (var i=0;i<length;i++){fn(elems[i],key, exec ? value.call(elems[i],i,fn(elems[i],key)) : value,pass);}return elems;}//读取属性return length ? fn(elems[0],key) : undefined;},

转载于:https://www.cnblogs.com/colorstory/p/2612959.html

相关文章:

HDU 5972 Regular Number(ShiftAnd+读入优化)

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid5972 【题目大意】 给出一个字符串&#xff0c;找出其中所有的符合特定模式的子串位置&#xff0c;符合特定模式是指&#xff0c;该子串的长度为n&#xff0c;并且第i个字符需要在给定的字符集合Si中 【题解】 利用Sh…

把握机缘_机缘巧合,蒙太奇训练以及我的朋友如何使自己失业

把握机缘by Wiley Jones通过威利琼斯 机缘巧合&#xff0c;蒙太奇训练以及我的朋友如何使自己失业 (Serendipity, training montages, and how my friend automated himself out of a job) “No one person’s Hollywood success story has anything in common with anybody e…

Servlet(一)

BS架构的优势 1.数据库之负责数据库的管理 2.Web服务器负责业务逻辑的处理 3.浏览器提供操作界面 4.不需要单独安装客户端 5.开发相对于CS简单&#xff0c;客户端和服务器的通信模块都是使用标准的HTTP协议进行通信 CS架构 1.数据库作为Server,使用数据库特定的编程语言编写业务…

visual webgui theme designer

转载于:https://www.cnblogs.com/jintan/p/3804095.html

51单片机编码自学_这是9个月的自学式编码看起来像什么

51单片机编码自学by Stephen Mayeux斯蒂芬马约(Stephen Mayeux) 这是9个月的自学式编码看起来像什么 (Here’s What 9 Months of Self-Taught Coding Looks Like) 只是划伤表面 (Just Scratching the Surface) Today marks 9 months since I embarked on my journey as a self…

19.Remove Nth Node From End of List

方法1&#xff1a;由于链表不能随机访问&#xff0c;所以很自然的想法是第一遍得到链表长度&#xff0c;然后计算倒数第n个结点的位置&#xff0c;但这样时间复杂度O(n2)&#xff0c;想到用空间换取时间&#xff0c;可以用一个地址数组存储每个结点的地址&#xff0c;然后直接删…

HTML 5中SEO可以用那些代码来做优化

头部代码 1、标题标签(title标签) 在HTML5中标题标签依然存在&#xff0c;其仍然具有不可替代的作用;不过我们看到还有更多的可供搜索引擎识别的代码&#xff0c;我们将改代码的等级微降。 2、元标签(meta标签) 字符集编码声明标签 该标签原本就是搜索引擎必看且首先要看的标签…

XCode 导入头文件不提示解决

File --> WorkSpace Settings ---> Build Sysytem ---> Legacy Build System

构建node.js基础镜像_在Android上构建Node.js应用程序

构建node.js基础镜像by Aurlien Giraud通过AurlienGiraud 在Android上构建Node.js应用程序-第1部分&#xff1a;Termux&#xff0c;Vim和Node.js (Building a Node.js application on Android - Part 1: Termux, Vim and Node.js) If you are excited about Node.js and own a…

MyEclipse设置默认的文档注释和背景色设置

转载于:https://www.cnblogs.com/999-/p/6086219.html

C语言之数组中你所不在意的重要知识

#include<stdio.h>void simpleArray();void main() {simpleArray();}//数组的简单操作 void simpleArray() {//数组的声明并赋值int c[5] { 1, 2, 3, 4, 5 };printf("\nC数组内存中占%d个字节",sizeof(c));// /0在内存中会占一个字节&#xff0c;可是仅仅针…

swift 4.0 创建tableview 自定义cell

// // ViewController.swift // AlamofileDemo // // Created by Alex on 2019/3/5. // Copyright © 2019 AlexanderYeah. All rights reserved. //import UIKit import Alamofire// 遵守协议方法 class ViewController: UIViewController,UITableViewDataSource,UITa…

ux体验网站 英国_?? 用户体验(UX)资源和工具的完整列表??

ux体验网站 英国by Jason Hreha杰森赫雷哈(Jason Hreha) ?? 用户体验(UX)资源和工具的完整列表?? (?? The Complete List of User Experience (UX) Resources & Tools ??) 超过100个链接&#xff0c;可以链接到最好的书籍&#xff0c;课程&#xff0c;新闻通讯和工…

Android 第三方图表类 MPChart 的使用

先看看条形图的的效果还不错是吧&#xff0c;实现这样的效果很合适呢&#xff01; 还有折线图、饼图很多效果 效果不错对吧~ 下面我们就先来看看条形图的实现方法吧&#xff01; 第一步&#xff1a; 引入第三方包 MPChart 如果你碰巧看过我之前写的Recycleview的博客这就简单多…

C++ STL的sort 函数 以及自定义的比较函数

没什么特别擅长的内容&#xff0c;先做个小笔记好了。在编程时&#xff0c;使用C的标准模板库&#xff08;STL&#xff09;能节约工作量&#xff0c;增加代码的可读性&#xff0c;能灵活运用无疑会提高编程的效率&#xff0c;俗话说&#xff1a;Write less, create more ~ 然后…

7-构造器方法

import UIKit// 1 构造器 // 结构体和类在实例的构造过程中会调用一种特殊的方法init&#xff0c;称之为构造器 // 构造器的主要作用是初始化存储属性 // 如果存储属性在构造器中没有初始化 在定义的时候也没有初始化 就会产生编译错误class Employee{let no:Int;var name:Stri…

模糊推理 控制 易于实现_代码“易于推理”是什么意思?

模糊推理 控制 易于实现by Preethi Kasireddy通过Preethi Kasireddy 代码“易于推理”是什么意思&#xff1f; (What does it mean when code is “easy to reason about”?) You’ve probably heard the expression “easy to reason about” enough times to make your ear…

简单介绍一下R中的几种统计分布及常用模型

统计学上分布有很多&#xff0c;在R中基本都有描述。因能力有限&#xff0c;我们就挑选几个常用的、比较重要的简单介绍一下每种分布的定义&#xff0c;公式&#xff0c;以及在&#xff32;中的展示。 统计分布每一种分布有四个函数&#xff1a;d――density&#xff08;密度函…

leetcode题解:Construct Binary Tree from Preorder and Inorder Traversal (根据前序和中序遍历构造二叉树)...

题目&#xff1a; Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that duplicates do not exist in the tree. 说明&#xff1a; 1&#xff09;二叉树可空 2&#xff09;思路&#xff1a;a、根据前序遍历的特点, 知前序序列…

swift string,Int,Double相互转换

import UIKitvar str "Hello, playground" // 1 字符串转Int Double Float var str1 "818"; // 转Int var val1 Int(str1); // 转Double var val2 Double(str1); // 转float var val3 Float(str1);// 如果是25.0 转 Int&#xff0c;则需要先转为Doubl…

classlist使用方法_如何通过使用HTML5的classList API在没有jQuery的情况下操作类

classlist使用方法by Ayo Isaiah通过Ayo Isaiah 如何通过使用HTML5的classList API在没有jQuery的情况下操作类 (How to manipulate classes without jQuery by using HTML5s classList API) As a front end developer, you often need to change CSS rules based on how a us…

键盘码 ascii码

ASCII码表 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 ASCII值 控制字符 0 NUT 32 (space) 64 96 、 1 SOH 33 &#xff01; 65 A 97 a 2 STX 34 ” 66 B 98 b 3 ETX 35 # 67 C 99 c 4 EOT 36 $ 68 D 100 d 5 ENQ 37 % 69 E 101 e 6 ACK 38 & 70 F 102 f 7 BEL …

Swift -布局框架SnapKit使用

SnapKit 1 安装 SnapKit github地址 2 文档地址 在线文档 // // ViewController.swift // SK_SnapKit // // Created by coder on 2019/3/6. // Copyright © 2019 AlexanderYeah. All rights reserved. //import UIKit import SnapKitclass ViewController: UIVie…

Hadoop概念学习系列之为什么hadoop/spark执行作业时,输出路径必须要不存在?(三十九)...

很多人只会&#xff0c;但没深入体会和想为什么要这样&#xff1f; 拿Hadoop来说&#xff0c;当然&#xff0c;spark也一样的道理。 输出路径由Hadoop自己创建&#xff0c;实际的结果文件遵守part-nnnn的约定。 如何指定一个已有目录作为Hadoop作业的输出路径&#xff0c;作业将…

已知环境静态障碍物避障_我女儿如何教我无障碍环境

已知环境静态障碍物避障by Drew通过德鲁 我女儿如何教我无障碍环境 (How my daughter taught me about accessibility) 在过去的几个月里&#xff0c;花了很多时间学习编程知识&#xff0c;这真是令人大开眼界。 面对似乎无穷无尽的技术和概念(即使是最简单的事物)&#xff0c…

IIS 部署 node.js ---- 基础安装部署

一些可能有用的相关文章&#xff1a; https://blogs.msdn.microsoft.com/scott_hanselman/2011/11/28/window-iisnode-js/ http://blog.csdn.net/puncha/article/details/9047311 20161123&#xff0c;这几天看了一些相关文章&#xff0c;觉得说的不太清楚&#xff0c;记录一下…

Qt中的 Size Hints 和 Size Policies

sizeHint 这个属性所保存的 QSize 类型的值是一个被推荐给窗口或其它组件&#xff08;为了方便下面统称为widget&#xff09;的尺寸&#xff0c;也就是说一个 widget 该有多大&#xff0c;它的一个参考来源就是这个 sizeHint 属性的值&#xff0c;而这个值由 sizeHint() 函数来…

atom 中首次使用git_使用Atom获得更好的Git提交消息

atom 中首次使用gitby Hasit Mistry通过Hasit Mistry 使用Atom获得更好的Git提交消息 (Get Better Git Commit Messages with Atom) Recently, I came across two enlightening posts about writing better Git commit messages. These posts give suggestions about how a we…

正确理解ThreadLocal

详见&#xff1a;http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt107 首先&#xff0c;ThreadLocal 不是用来解决共享对象的多线程访问问题的&#xff0c;一般情况下&#xff0c;通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象&#xff0c;其他线程…

PHP-密码学算法及其应用-对称密码算法

转自&#xff1a;http://www.smatrix.org/bbs/simple/index.php?t5662.html //目录1. PHP的散列函数及其应用2. PHP中的对称密码算法及其应用3. PHP的公钥密码算法及其应用///2 PHP中的对称密码算法及其应用前一段时间一直想写完PHP中的密码学算法及其应用的三大部分…