Jquery操作checkbox,出現無法解除選定問題

源代碼:

function changeSelect(obj){
    var checkBox = $(obj);
    if (checkBox.prop("checked")) {
	    checkBox.attr("checked", false);
    } else {
	    checkBox.attr("checked", true);
    }
}

出現的問題:

     選定---取消選定---再選定,進行以上操作後,無法取消選定

解決辦法:

function changeSelect(obj){
    var checkBox = $(obj);
    if (checkBox.prop("checked")) {
	    checkBox.prop("checked", false);
    } else {
	    checkBox.prop("checked", true);
    }
}

原因:引自:https://blog.csdn.net/dszgf5717/article/details/51853885

摘錄:

一直都在用 jQuery 1.8.3 的版本,沒有嘗試過 jQuery 1.9.0 的版本。

於是,開始調試代碼,在 1.9.0 的版本中:

<input type="checkbox" />

<script>

$(function() {

    $('input').click(function() {

        $(this).attr('checked');

    });

});

</script>

點擊 checkbox,結果都是 undefined

而在 1.8.3 的版本中,結果是 checked 和 undefined

到這裏,問題答案找到了,就是使用 attr() 方法的問題,於是查看官方文檔, 才知道從 jQuery 1.6 開始新增了一個方法 prop(),但是一直都沒有使用過。

從中文意思看,兩者分別是獲取/設置 attributes 和 properties 的方法,那麼爲什麼還要增加 prop() 方法呢?

Before jQuery 1.6, the .attr() method sometimes took property values into account when retrieving some attributes, which could cause inconsistent behavior.

因爲在 jQuery 1.6 之前,使用 attr() 有時候會出現不一致的行爲。

那麼,什麼時候使用attr(),什麼時候使用prop()?

To retrieve and change DOM properties such as the checked, selected, or disabled state of form elements, use the .prop() method. 

根據官方的建議:具有 true 和 false 兩個屬性的屬性,如 checked, selected 或者 disabled 使用prop(),其他的使用 attr()

到此,將 attr('checked') 改成 prop('checked') 即可修復提的 issues 了。

^_^

等等,貌似問題還沒真正解決,爲什麼開頭例子中 jQuery 1.8.3 和 1.9.0 使用 attr() 會有所區別呢?

想知道他們的區別,最好的辦法還是看他們的源代碼:

1.8.3 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;

    }

}

1.9.0 attr():

attr: function( elem, name, value ) {

    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;

    }


    // 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 );

        } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {

            return ret;

        } else {

            elem.setAttribute( name, value + "" );

            return value;

        }

    } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
        return ret;
    } else {


    // In IE9+, Flash objects don't have .getAttribute (#12945)

    // Support: IE9+

    if ( typeof elem.getAttribute !== "undefined" ) {

        ret = elem.getAttribute( name );

    }


    // Non-existent attributes return null, we normalize to undefined

    return ret == null ?undefined :ret;

    }

}

1.8.3 和 1.9.0 的 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() 和 prop() 的區別:

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,這是轉化成 element 的一個屬性。

對比調試 1.9.0 和 1.8.3 的 attr() 方法,發現兩者的區別在於

hooks.get( elem, name )) 

返回的值不一樣,具體的實現:

1.8.3 中

boolHook = {

    get: function( elem, name ) {

        // Align boolean attributes with corresponding properties

        // Fall back to attribute presence where some booleans are not supported

        var attrNode,

        property = jQuery.prop( elem, name );

        return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?name.toLowerCase() :undefined;

    }

}

1.9.0 中


 
boolHook = {

    get: function( elem, name ) {

        var

        // Use .prop to determine if this attribute is understood as boolean

        prop = jQuery.prop( elem, name ),


        // Fetch it accordingly

        attr = typeof prop === "boolean" && elem.getAttribute( name ),

        detail = typeof prop === "boolean" ?


        getSetInput && getSetAttribute ?

        attr != null :

        // oldIE fabricates an empty string for missing boolean attributes

        // and conflates checked/selected into attroperties

        ruseDefault.test( name ) ?elem[ jQuery.camelCase( "default-" + name ) ] :

        !!attr :


        // fetch an attribute node for properties not recognized as boolean

        elem.getAttributeNode( name );


        return detail && detail.value !== false ?

        name.toLowerCase() :

        undefined;

    }

}

由此可見,1.9.0 開始不建議使用 attr() 來對具有 true 和 false 兩個屬性的屬性進行操作了。

那麼我們的結論是:

具有 true 和 false 兩個屬性的屬性,如 checked, selected 或者 disabled 使用prop(),其他的使用 attr()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章