您好,登錄后才能下訂單哦!
今天主要分析一下jQuery設置元素DOM屬性的相關方法的具體實現:addClass()、attr()、hasClass()、html()、prop()、removeAttr()。
首先是addClass():
// 該方法用于向元素添加新類名 addClass: function( value ) { var classNames, i, l, elem, setClass, c, cl; // 如果參數是函數的話,執行該分支語句 if ( jQuery.isFunction( value ) ) { // each方法在jQuery中經常用到,因為我們操作的jQuery對象經常是多個,該方法可以讓每個jQuery對象都執行相應的操作 return this.each(function( j ) { /* 這里用到了Function.call(),這也是在jQuery內部實現中經常用到的
還有與之類似的Function.apply()。二者都是用于改變運行上下文,
借用已存在的方法進行操作,不同點就是傳遞參數的方式
*/ jQuery( this ).addClass( value.call(this, j, this.className) ); }); } // 如果參數是字符串的話,執行該分支語句 if ( value && typeof value === "string" ) { // core_rspace = /\s+/,用于匹配一個及以上的空白字符 classNames = value.split( core_rspace ); // 將提供的參數按空白字符分開放到一個數組里 for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; // 確保元素是元素節點 if ( elem.nodeType === 1 ) { // 如果元素的class類名不存在而且新添加的類名只有一個 if ( !elem.className && classNames.length === 1 ) { elem.className = value; // 直接將參數賦值給class屬性 } else { // 在元素原有的class類名字符串前后添加空白字符可以保證添加新的類名后和原來的類名不會連到一塊,從而導致錯誤 setClass = " " + elem.className + " "; for ( c = 0, cl = classNames.length; c < cl; c++ ) { // 確保新添加的className在原來的元素的class屬性中不存在 if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) { setClass += classNames[ c ] + " ";// 加“ ”可以保證類名不會連接到一塊 } } // jQuery.trim方法用于去除字符串前后空格 elem.className = jQuery.trim( setClass ); } } } } // 形成鏈式調用 return this; }
該方法為每個匹配的元素添加指定的類名,共有兩種使用方法:
addClass( className )
className為每個匹配元素所要增加的一個或多個樣式名。
- addClass(function(index, currentClass))
function(index, currentClass)這個函數返回一個或更多用空格隔開的要增加的樣式名。接收元素的索引位置index和元素舊的樣式名currentClass作為參數。
在該方法里有一個易錯點,就是訪問元素的class屬性不可用elem.class,因為class是ECMAScript規范中的保留字,在將來可能會在語言規范中用到,所以需要用elem.className。與之相似的是訪問元素style屬性的float屬性,需要用elem.style.cssFloat和elem.style.styleFloat,還有for屬性,應該用htmlFor。
attr()方法:
attr: function( name, value ) { return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); }
怎么樣,看著簡單吧?該方法的作用就是取得第一個匹配元素的屬性值或者為指定元素設置一個或多個屬性。但是將該方法可以衍生出許多高級用法。不過我們一般就是用于直接設置和獲取屬性值。與之類似的還有prop()方法和html()方法:
prop: function( name, value ) { return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); }
html: function( value ) { return jQuery.access( this, function( value ) { var elem = this[0] || {}, i = 0, l = this.length; if ( value === undefined ) { return elem.nodeType === 1 ? elem.innerHTML.replace( rinlinejQuery, "" ) : undefined; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1></$2>" ); try { for (; i < l; i++ ) { // Remove element nodes and prevent memory leaks elem = this[i] || {}; if ( elem.nodeType === 1 ) { jQuery.cleanData( elem.getElementsByTagName( "*" ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch(e) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }
prop方法一般用于獲取在匹配的元素集中的第一個元素的屬性值。高級用法是設置為匹配的元素設置一個或更多的屬性。
html方法用于從匹配的第一個元素中獲取或設置HTML內容。
這三個方法都用到了jQuery.access方法:
該方法當設置/獲取屬性的時候遍歷jQuery對象,依次調用fn函數。這里的fn可能是jQuery.attr和jQuery.prop。需要注意的是這里用for遍歷elems,這個elems實際是jQuery對象,jQuery對象它是一個ArrayLike。大概就是如此,剩下的一堆hooks是用來解決瀏覽器兼容性的問題。如jQuery.attrHooks、jQuery.propHooks、jQuery.valHooks。列舉如下
也許以后我會專門寫篇博客來分析這個方法。它是一個多功能的方法,用于獲取和設置集合中的值,我們只要知道這一點就行了。
hasClass():
hasClass: function( selector ) { var className = " " + selector + " ", i = 0, l = this.length; for ( ; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { return true; } } return false; }
該方法用于檢查匹配的元素是否含有某個特定的類selector。將參數selector轉換為" " + selector + " "是為了防止如果元素的class屬性中如果出現“sub selector-sup”的情況,這時如果直接用selector匹配的話,因為“selector-sup”的出現就會導致匹配正確,但實際上元素的class屬性中并沒有selector類名,只不過class屬性字符串中存在該字符串,從而導致錯誤。在參數前后添加空格后可以避免這個錯誤,但同時我們知道在元素的class屬性中,前后兩個類名的前/后面是沒有空格的,所以我們需要把className經過" " + this[i].className + " "處理。l = this.length;用于緩存操作的jQuery對象集合的長度,這種方式使我們在寫JavaScript中應該存在的意識,尤其是在DOM操作中。for循環是為了讓元素集合中的每一項都執行該操作,在這里就是每個都檢查一下是否存在selector類名,如果其中有一項不符合,則整個不匹配。在for循環中,this[i].nodeType === 1可以保證我們將要操作的節點是元素節點,而不是文本節點等其他節點,jQuery這種安全保障機制是值得我們學習的。replace(rclass, " ")中的rclass = /[\t\r\n]/g,是把class屬性中的制表符、回車符、換行符替換成空格,形成統一的“ class1 class2 class3 class4 class5 ”效果,然后再indexOf檢索特定的className是否存在。這還是一種安全保障機制,jQuery真是步步為營!
removeAttr()方法:
removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }
該方法只接受一個參數,為匹配的元素集合中的每個元素中移除一個name屬性。這里用到了jQuery.removeAttr():
/* 這里用到了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" },它用于修正IE瀏覽器中的IE6、7getAttribute、setAttribute、removeAttribute等方法的不足 */ removeAttr: function( elem, value ) { var propName, attrNames, name, isBool, i = 0; // 確保要移除的屬性存在,并且節點是元素節點 if ( value && elem.nodeType === 1 ) { // 將參數value按空格分解成數組 attrNames = value.split( core_rspace ); // 對要移除的屬性數組一個一個移除 for ( ; i < attrNames.length; i++ ) { name = attrNames[ i ]; if ( name ) { // 確保要移除的屬性存在非空 propName = jQuery.propFix[ name ] || name; // 修正IE部分瀏覽器獲取屬性的錯誤 // rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i isBool = rboolean.test( name ); // 檢查要設置的屬性是否是boolean值控制的 // 直接對非boolean值控制的屬性進行賦空值,也就是移除 if ( !isBool ) { jQuery.attr( elem, name, "" ); } // div = document.createElement("div"); getSetAttribute: div.className !== "t"檢查是否支持setAttribute,主要針對IE6/7 elem.removeAttribute( getSetAttribute ? name : propName ); // 如果該屬性由boolean值控制,并且修正后的屬性是元素的屬性,雙重保險 if ( isBool && propName in elem ) { elem[ propName ] = false; } } } } }
明天繼續分析removeClass()、removeProp()、toggleClass()、val()。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。