jquery1.6版本后引入了prop()方法,很多时候总是混淆attr()与prop()这俩,下面分析一下这俩的区别

在此之前,先来了解一下html 的attribute和property,因为jquery的attr()和prop()正是来源于这俩东西。先看一段html代码:

<span  id="testId" class="testClass" selfAttribute="selfValue"></span>

根据 DOM (HTML) 规范,SPAN 元素在页面中生成一个相对应的对象,对象有一个标识为id的attribute,对于attribute,我们称为HTML标签属性,对于property,为DOM对象属性,注意下面这句话:

HTML 标签的属性会将其值暴露给对应的 DOM 对象的属性,如 HTML 元素的 id 属性与其对应的 DOM 对象的 id 属性会保持一种同步关系

所以该元素的dom对象中也会生成key为id的 property,所以可以通过key直接获得值,看下面的例子

var testId =  document.getElementById("testId");
console.log(testId.id);//testId
console.log(testId.getAttribute("id"));//testId

这样一来是不是以后获取属性值都直接用.访问就可以了,下面继续看:

 var testId =  document.getElementById("testId");
 console.log(testId.class);//undefinde
 console.log(testId.getAttribute("class"));//testClass

当我们直接访问class时,并没有得到我们期望的testClass,原因是在 HTML 标签中使用 class 属性指定元素使用的 CSS 类,但在 DOM 对象中由于 class 是 ECMAScript 的保留字,所以改用 className 属性,所以想直接获取class值,修改一下即可:

console.log(testId.className);//testClass

上面的例子可以知道 ,对于部分 "property" 与 "attribute" 在名称及值类型上是统一的,对于我们经常用到的自定义属性,可以继续做个测试:

 var testId =  document.getElementById("testId");
 console.log(testId.selfAttribute);//undefined
 console.log(testId.getAttribute("selfAttribute"));//selfValue

testId.selfAttribute为undefined说明property与attribute并不共享自定义属性,引用别人的一张图来表示一下:

    

对于build-in区域的属性,property和attribute是共享的,比如id,但是IE6、7没有作区分,依然共享自定义属性数据,因为IE 混淆了 DOM 对象属性(property)及 HTML 标签属性(attribute),造成了对 setAttribute、getAttribute 的不正确实现,参考http://www.w3help.org/zh-cn/causes/SD9006

对于自定义的属性两者互不干涉,即使name是相同的,看下面例子:

 

 var testId =  document.getElementById("testId");
       testId.setAttribute("stk1","stv1");
       console.log(testId.stk1);//undefined
       console.log(testId.getAttribute("stk1"));//selfValue
       testId.stk1 = "stv2";
       console.log(testId.stk1);//stv2
       console.log(testId.getAttribute("stk1"));//stv1

此外,对于值是true/false的property,类似于input的checked attribute等,attribute取得值是HTML文档字面量值,property是取得计算结果,property改变并不影响attribute字面量,但attribute改变会影响property计算

<input type="checkbox" id="checkboxId"/>
var checkbox1 =  document.getElementById("checkboxId");
       
         alert(checkbox1.checked);//false
         alert(checkbox1.getAttribute("checked"));//null

        /* checkbox1.setAttribute("checked","checked");
         alert(checkbox1.checked);//true, setAttribute影响property*/

         checkbox1.checked = true;
         alert(checkbox1.getAttribute("checked"));//null property不影响setAttribute影响property

对于一些和路径相关的属性,两者取得值也不尽相同,但是同样attribute取得是字面量,property取得是计算后的完整路径

<a id="testA" href="#">Click</a>

 

 var testA =  document.getElementById("testA");
 console.log(testA.href);//file:///C:/Users/%E6%B0%B8%E4%BF%A1/Desktop/static/main.html# 
 console.log(testA.getAttribute("href"));//#

看完上面的文章,看一下主题,attr() 和 prop()

首先贴源码:

attr:

attr: function( elem, name, value, pass ) {
    var ret, hooks, notxml,
        nType = elem.nodeType;
    // don't get/set attributes on text, comment and attribute nodes
    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
        return;
    }
    if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
        return jQuery( elem )[ name ]( value );
    }
    // Fallback to prop when attributes are not supported
    if ( typeof elem.getAttribute === "undefined" ) {
        return jQuery.prop( elem, name, value );
    }
    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
    // All attributes are lowercase
    // Grab necessary hook if one is defined
    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;
    }
}

prop:

prop: function( elem, name, value ) {
    var ret, hooks, notxml,
        nType = elem.nodeType;
    // don't get/set properties on text, comment and attribute nodes
    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
        return;
    }
    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
    if ( notxml ) {
        // Fix name and attach hooks
        name = jQuery.propFix[ name ] || name;
        hooks = jQuery.propHooks[ name ];
    }
    if ( value !== undefined ) {
        if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
            return ret;
        } else {
            return ( elem[ name ] = value );
        }
    } else {
        if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
            return ret;
        } else {
            return elem[ name ];
        }
    }
}

attr方法里面,最关键的两行代码,elem.setAttribute( name, value + “” )和ret = elem.getAttribute( name ),很明显的看出来,使用的DOM的API setAttribute和getAttribute方法操作的属性元素节点
而prop方法里面,最关键的两行代码,return ( elem[ name ] = value )和return elem[ name ],你可以理解成这样document.getElementById(el)[name] = value,这是转化成JS对象的一个属性。

再来看例子:

<input type="checkbox" id="test" abc="111" />
$(function(){
    el = $("#test");
    console.log(el.attr("style"));  //undefined
    console.log(el.prop("style"));  //CSSStyleDeclaration对象
    console.log(document.getElementById("test").style); //CSSStyleDeclaration对象
});
  1. el.attr(“style”)输出undefined,因为attr是获取的这个对象属性节点的值,很显然此时没有这个属性节点,自然输出undefined
  2. el.prop(“style”)输出CSSStyleDeclaration对象,对于一个DOM对象,是具有原生的style对象属性的,所以输出了style对象
  3. 至于document.getElementById(“test”).style和上面那条一样
el.attr("abc","111")
console.log(el.attr("abc")); //111
console.log(el.prop("abc")); //undefined

首先用attr方法给这个对象添加abc节点属性,值为111,可以看到html的结构也变了

  1. el.attr(“abc”)输出结果为111,再正常不过了
  2. el.prop(“abc”)输出undefined,因为abc是在这个的属性节点中,所以通过prop是取不到的

我们再接着来:

el.prop("abc", "222");
console.log(el.attr("abc")); //111
console.log(el.prop("abc")); //222

我们再用prop方法给这个对象设置了abc属性,值为222,可以看到html的结构是没有变化的。输出的结果就不解释了。

提一下,在遇到要获取或设置checked,selected,readonly和disabled等属性时,用prop方法显然更好,比如像下面这样:

<input type="checkbox" id="test" checked="checked" />
console.log(el.attr("checked")); //checked
console.log(el.prop("checked")); //true
console.log(el.attr("disabled")); //undefined
console.log(el.prop("disabled"));  //false

关于checked 属性需要记住的最重要的一点是:它和checked property并不是一致的。实际上这个attribute和defaultChecked property一致,而且只应该用来设置checkbox的初始值。checked attribute并不随着checkedbox的状态而改变,但是checked property却跟着变。因此浏览器兼容的判断checkebox是否被选中应该使用property

posted on 2014-07-24 18:08  Earlene  阅读(216)  评论(0编辑  收藏  举报