欢迎来我的专栏检察系列文章。
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"></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 和之前略有差别,又多了一层,但基础思路是一致的。
外部扩大 Hooks
jQuery 内部的 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 class="body" class-sp="test"></body>
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。
欢迎来我的博客交换。