深入瀏覽器相容 細數jQuery Hooks 屬性篇
本章的目的很簡單,通過鉤子函式更細節的瞭解瀏覽器差異與處理方案,
版本是2.0.3所以不相容ie6.7.8,所以對應了鉤子會少很多。。
總的來說鉤子在.attr()
, .prop()
, .val()
and .css() 四種操作中會涉及
屬性操作的鉤子
propFix
propHooks
attrHooks
valHooks
jQuery.propFix 中的物件
原始碼部分
1:保留值屬性名字修正
jQuery.propFix: { for : "htmlFor", class : "className" },
- 由於class屬於JavaScript保留值,因此當我們要操作元素的class屬性
- 同理htmlFor用於讀取label標籤的for屬性
測試demo,通過class與className修改元素的屬性
2:與表單操作相關:
反轉下,讓鉤子適配用虛擬碼匹配,目測應該是為了相容開發者輸入大小寫格式不正確
比如輸入錯誤格式:cellpadding
如果jQuery.propFix 轉成cellPadding ,駝峰寫法了
jQuery.each([ "tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable" ], function() { jQuery.propFix[ this.toLowerCase() ] = this; });
tabIndex 屬性可設定或返回按鈕的 tab 鍵控制次序
readonly 屬性規定輸入欄位為只讀。
maxlength 屬性規定輸入欄位的最大長度,以字元個數計。
cellspacing 屬性規定單元格之間的空間
cellpadding 屬性規定單元邊沿與其內容之間的空白。
rowspan 屬性規定單元格可橫跨的行數。
colspan 屬性規定單元格可橫跨的列數。
HTML <img> 標籤的
usemap 屬性將影象定義為客戶端影象對映
frameBorder 屬性設定或返回是否顯示框架周圍的邊框。
contenteditable 屬性規定是否可編輯元素的內容。
值得一提的是這個方法用的比較巧妙了,收集所有的合集名,然後在每一個上下文回撥中把每一個名字傳遞到propFix方法,key轉成小寫,value儲存正確寫法
jQuery.propFix[ this.toLowerCase() ] = this;
jQuery.propHooks 屬性方法
關於tabIndex屬性
propHooks: { tabIndex: { get: function( elem ) { return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ? elem.tabIndex : -1; } } }
// Support: IE9+ // Selectedness for an option in an optgroup can be inaccurate if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = { get: function( elem ) { var parent = elem.parentNode; if ( parent && parent.parentNode ) { parent.parentNode.selectedIndex; } return null; } }; }
jQuery.attrHooks 方法
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; } } } },
jQuery.valHooks 方法
根據 JQuery api文件 的描述,.val() 函式有兩種用法,分別用來獲取或設定元素的值,這裡只介紹獲取值的方法。
文件裡面說 .val 主要是用於獲取元素的value,比如 input, select 和 textarea等,
什麼是元素的value?”
用 select 標籤為例,如下的程式碼:
測試程式碼
<select id="choise"> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> <option value="4">Four</option> </select>
這裡的option有2個值,一個是value = 1 另一個則是 text = One
option 真正的 value 應該是其 value 屬性中的值,而不是 option 標籤中間所包含的內容
在 w3school 的文件中對 option 的 value 屬性的做了如下定義:
The value attribute specifies the value to be sent to a server when a form is submitted. The content between the opening <option> and closing </option> tags is what the browsers will display in a drop-down list. However, the value of the value attribute is what will be sent to the server when a form is submitted. Note: If the value attribute is not specified, the content will be passed as the value instead.
這一點對於所有可以擁有 value 屬性的標籤都是相同的,即在對一個元素呼叫 .val() 函式時,首先取其 value 屬性的值,如果沒有的話,再使用其 text值。
那麼接下來就要引入我們的valHooks,針對option,select的處理
valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, option, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one" || index < 0, values = one ? null : [], max = one ? index + 1 : options.length, i = index < 0 ? max : one ? index : 0; // Loop through all the selected options for ( ; i < max; i++ ) { option = options[ i ]; // IE6-9 doesn't update selected after form reset (#2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } return values; }, set: function( elem, value ) { var optionSet, option, options = elem.options, values = jQuery.makeArray( value ), i = options.length; while ( i-- ) { option = options[ i ]; if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) { optionSet = true; } } // force browsers to behave consistently when non-matching value is set if ( !optionSet ) { elem.selectedIndex = -1; } return values; } } },
對於val方法的取值部分
if ( elem ) { hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; }
通過jQuery.valHooks匹配對應的鉤子處理方法
節點屬性的差異對比:
select : 建立單選或多選選單
- type:"select-one"
- tagName: "SELECT"
- value: "111"
- textContent: "↵ Single↵ Single2↵"
option : 元素定義下拉列表中的一個選項
- tagName: "OPTION"
- value: "111"
- text: "Single"
- textContent: "Single"
radio : 表單中的單選按鈕
- type: "radio"
- value: "11111"
checkbox : 選擇框
- type: "checkbox"
- value: "11111"
根據對比select的節點type是'select-one’與其餘幾個還不同,所以jQuery在適配的時候採用優先查詢type,否則就找nodeName的策略
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
如果鉤子匹配到了,並且還存在get方法,那麼就要呼叫這個方法了,如果有返回值就返回當前的這個最終值
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; }
那麼具體的相容問題就會跑到對應的鉤子方法中處理了
// Loop through all the selected options for ( ; i < max; i++ ) { option = options[ i ]; // IE6-9 doesn't update selected after form reset (#2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } }
通過selectedIndex 屬性可設定或返回下拉列表中被選選項的索引號
通過遞迴select中的所有option
在包裝jQuery( option ).val()
從而呼叫option的鉤子方法get ,
get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; }
elem.attributes.value返回對應的option的val值
所以這裡就相容的預設返回val,否則就返回text的內容了
radio,checkbox
// Radios and checkboxes getter/setter jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); } } }; if ( !jQuery.support.checkOn ) { jQuery.valHooks[ this ].get = function( elem ) { // Support: Webkit // "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; }; } });
如果您看完本篇文章感覺不錯,請點選一下右下角的【推薦】來支援一下博主,謝謝!
如果是原創文章,轉載請註明出處!!!