摘要:歡迎來我的專欄查看系列文章。算是中一個非常可以借鑒的用法,以前聽到這個概念是非常恐懼的,當看了源碼,弄懂原理之后,發現超級有意思。參考源碼分析鉤子機制屬性操作源碼學習本文在上的源碼地址,歡迎來。
歡迎來我的專欄查看系列文章。
hooks 在英語中的意思表示鉤子或掛鉤,在 jQuery 中也有 hooks 這么一個概念,它的功能在考慮到一些兼容性和其它特殊情況的條件下,優先考慮這些特殊情況,而后才去用普通的方法處理,這種說法還是比較形象的。
hooks 的使用非常用技術含量,可以支撐在原來的基礎上擴展,而對于接口則無需改變,舉個例子,像 fn.css() 這個函數我們都是非常熟悉的了,拿來就用,而不需要考慮瀏覽器的兼容性,這里的兼容性包括 border-radius 兼容,使用的時候不需要在前面加上 -webkit- 瀏覽器標識。而 css 函數的內部則是借助 $.cssHooks()來實現這種“鉤子”的效果的,擴展的時候,也是在這個對象上進行擴展。
先來說說 attr 和 prop不急著上來就談 hooks,先來看看 hooks 涉及到的應用。一個典型的應用就是 fn.attr 和 fn.prop,這兩個原型函數的作用是用來給 jQuery 對象綁定元素的,如果不了解,可以參考這兩個鏈接,attr,prop。
雖然它們都是添加屬性,卻是不同的方式,其中,attr 是把屬性放到 html 中(實際上是 elem.attributes 屬性),而 prop 是把屬性添加到 dom 對象上,可以通過 [.] 來讀取。
那么什么叫做 html 中?就是我們常說的 data- 數據:
var body = $("body"); body.attr("data-name","body"); // body.data("name"); //"body"
attr 方法是對應于 jQuery 中的方法,而內部是通過 setAttribute,getAttribute 這種低級 api 來實現的,而且在 dom 對象的 attributes 屬性上是可以找到綁定值的,所以 attr 和 prop 是兩種不同的方法。
這兩個函數有四個功能,分別包括讀取和設置,如果參數只有一個,表示讀(如果參數是 Object 另外考慮),參數為兩個,表示寫。
當然,除此之外,還有 removeAttr 和 removeProp 方法,源碼如下:
jQuery.fn.extend({ attr: function (name, value) { return access(this, jQuery.attr, name, value, arguments.length > 1); }, removeAttr: function (name) { return this.each(function () { jQuery.removeAttr(this, name); }); }, prop: function (name, value) { return access(this, jQuery.prop, name, value, arguments.length > 1); }, removeProp: function (name) { return this.each(function () { delete this[jQuery.propFix[name] || name]; }); } })access 方法
先看 attr 和 prop,都是通過 access 函數,至少傳入的參數不同,一個是 jQuery.attr,一個是 jQuery.prop。來看看 access:
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, len = elems.length, bulk = key == null; // 參數為對象,一次性設置多個值 if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); } // 設置一個值 } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } // key 為 null 的情況 if ( bulk ) { if ( raw ) { fn.call( elems, value ); fn = null; // value 為 function } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } // 函數執行在這里 if ( fn ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } if ( chainable ) { // 寫情況的返回值 return elems; } // Gets if ( bulk ) { return fn.call( elems ); } // 這個返回值是比較熟悉的,即 get return len ? fn( elems[ 0 ], key ) : emptyGet; }
access 不是今天的重點,函數不是很難,源碼讀起來挺有意思。
attr 和 prop 源碼來看看 jQuery.attr 和 jQuery.prop:
jQuery.attr = function (elem, name, value) { var ret, hooks, nType = elem.nodeType; // 對于 text, comment 和 attribute nodes 不處理 if (nType === 3 || nType === 8 || nType === 2) { return; } // 如果連這個函數都不支持,還是用 prop 方法吧 if (typeof elem.getAttribute === "undefined") { return jQuery.prop(elem, name, value); } // 先處理 hooks,優先考慮非正常情況 if (nType !== 1 || !jQuery.isXMLDoc(elem)) { hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : undefined); } // value 為 underfined 的時候調用 remove if (value !== undefined) { if (value === null) { jQuery.removeAttr(elem, name); return; } // hooks.set if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) { return ret; } // 非 hooks 情況,正常 set elem.setAttribute(name, value + ""); return value; } // hooks.get if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { return ret; } // 正常 get 方法 ret = jQuery.find.attr(elem, name); // Non-existent attributes return null, we normalize to undefined return ret == null ? undefined : ret; }
jQuery.prop = function (elem, name, value) { var ret, hooks, nType = elem.nodeType; // Don"t get/set properties on text, comment and attribute nodes if (nType === 3 || nType === 8 || nType === 2) { return; } if (nType !== 1 || !jQuery.isXMLDoc(elem)) { // 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; } return elem[name] = value; } if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) { return ret; } return elem[name]; }
可以看得出來,jQuery.attr 和 jQuery.prop 方法是真的非常像,但是如果你不懂 hooks,可能會有很不疑問,這個不急。可以總結出大致的處理流程:先判斷 dom 類型,然后根據一些特殊情況,復制 hooks 參數,這里的特殊條件為 (nType !== 1 || !jQuery.isXMLDoc(elem)),接著對于 set 和 get 方法判斷,通過 value 值是否為 underfined,如果 hooks 中有,用 hooks 中提供的方法,沒有,就走正常流程。
初識 hooks已經知道在哪里使用 hooks,那么 hooks 長什么樣呢:
jQuery.extend({ attrHooks: { // attrHooks 兼容 type 的低版本瀏覽器的情況 type: { set: function( elem, value ) { if ( !support.radioValue && value === "radio" && jQuery.nodeName( elem, "input" ) ) { var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } } }, propHooks: { tabIndex: { get: function( elem ) { ... } } } }) // jQuery 內部擴展 // 對于不支持 selected 的情況 if(!support.optSelected){ jQuery.propHooks.selected = { get: function(){ ... }, set: function(){ } } }
在 attr 的 attrHooks 中,用來處理的特殊情況是 name=type 的情況,或許是這種情況,type 綁定不到 html 中。在 prop 的 propHooks 中,處理的特殊情況是 tabIndex,下面還擴展了一個 selected 方法,如果瀏覽器不支持 select,就建一個 hooks。
所以一個基本的 Hooks(jQuery 內部的)應該長這樣:
jQuery.extend({ nameHooks: { get: function(){ ... }, set: function(){ ... }, other: function(){ ... } } })
get 和 set 是非必需的,這是因為 attr 和 prop 的特殊性造成的,在看一個例子 jQuery.fn.val,val 的介紹 jQuery.val,val 也有一個 valHooks 與之對應:
jQuery.extend({ valHooks: { option: { get: function(){...} }, select: { get: function(){...}, set: function(){...} } } })
valHooks 和之前略有不同,又多了一層,但基本思路是一致的。
外部擴展 HooksjQuery 內部的 hooks 功能是非常強大的,不過令人感覺欣慰的是可以在外部擴展。
比如有一個問題,我們之前解釋 attr 的時候,知道它可以添加 html 的 attribute,但有一些固有的,比如 class,我們就是想在它上面添加,但又不能影響原有的 class 屬性,可以這樣來修改:
jQuery.attrHooks.class = { // 這里的參數順序后面兩個是相反的 set: function(elem, value){ return $(elem).attr("class-sp", value); }, get: function(elem){ return $(elem).attr("class-sp"); } } //測試 body.attr("class","test"); // body.attr("class"); // "test"
perfect!
總結Hooks 講這么多,應該就 ok 了。Hooks 算是 jQuery 中一個非常可以借鑒的用法,以前聽到這個概念是非常恐懼的,當看了源碼,弄懂原理之后,發現超級有意思。
仍然有不足,比如 jQuery 中一個非常有重量級的 cssHooks 就沒有提到,還是腳踏實地吧。
參考jQuery 2.0.3 源碼分析 鉤子機制 - 屬性操作
jQuery Hooks
jQuery.cssHooks
jQuery.val
jQuery hooks源碼學習
本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81781.html
摘要:專門為事件建立一個有問題,直接退出如果是一個事件處理對象,且有屬性。參考源碼分析事件體系結構解密事件核心綁定設計一解密事件核心委托設計二本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 通過前面一章對于 addEvent 庫的介紹,它的兼容性超級棒,據說對于 IE4、5 都有很好的兼容性,這和 jQuery 的原理是一致的,而在 jQuery 中,有一個對象與其相對應,那就是...
摘要:干想了半天,認為可能還是本身的寫法問題。對象提供了一種通過定義函數來獲取或設置特定值的方法。簡單來說,給我們暴露了一個鉤子,我們可以自己定義方法比如,來實現針對某個屬性的特定行為。 寫在最前 本次分享一下在一次jQuery賦值樣式失效的結果中來分析背后原因的過程。在翻jQuery源碼的過程中,感覺真是還不能說自己只是會用jQuery,我好像連會用都達不到(逃 歡迎關注我的博客,不定期更...
摘要:干想了半天,認為可能還是本身的寫法問題。對象提供了一種通過定義函數來獲取或設置特定值的方法。簡單來說,給我們暴露了一個鉤子,我們可以自己定義方法比如,來實現針對某個屬性的特定行為。 寫在最前 本次分享一下在一次jQuery賦值樣式失效的結果中來分析背后原因的過程。在翻jQuery源碼的過程中,感覺真是還不能說自己只是會用jQuery,我好像連會用都達不到(逃 歡迎關注我的博客,不定期更...
摘要:作為此時不存在,直接從數據緩存中獲取并返回。作用是觸發中的回調函數,的表示只讓觸發一次后,就需要清理,表示是將清空成空數組還是空字符。 showImg(https://segmentfault.com/img/remote/1460000019558449); 前言:queue()方法和dequeue()方法是為 jQuery 的動畫服務的,目的是為了允許一系列動畫函數被異步調用,但不...
閱讀 2975·2021-11-24 10:22
閱讀 3044·2021-11-23 10:10
閱讀 1352·2021-09-28 09:35
閱讀 1752·2019-08-29 13:16
閱讀 1395·2019-08-26 13:29
閱讀 2782·2019-08-26 10:27
閱讀 677·2019-08-26 10:09
閱讀 1435·2019-08-23 18:05