其實在jQuery1.5中已有這東西,cssHooks,或者更早之前的jQuery.event.special, 或者 Sizzle.selectors裡面更多的對象。它們共同的特點是包含了許多相關的函數,cssHooks是專門處理css屬性的擷取與設定,如IE的opacity,event.special用於裝載與卸載submit, change, focus ,mouseenter等特別事件與自訂事件, Sizzle.selectors裡面的過濾器與候選集擷取器就更不用說了。由於JS用對象做為表進行尋找是比if條句與switch語句快很多,加之,適配器這種模式對於擴充新功能非常有利,因為jQuery1.6便把它發揚光大了。
在jQuery的attributes模組(github是這樣分割的,但耦合這麼高很難說是模組),共增加了三個這樣對象,valHooks,attrHooks, propHooks,分別對應val,attr與prop這個三個方法。prop是新增的,表示jQuery決定區分屬性與特性的決心,但IE6/7還是無法區分它們,因此attr基本上涵蓋了prop的功能。
我們看一下它們各自的運用吧!
// jQuery.style 方法 if ( value !== undefined ) { //=================略============== // If a hook was provided, use that value, otherwise just set the specified value if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) { // Wrapped to prevent IE from throwing errors when 'invalid' values are provided // Fixes bug #5509 try { style[ name ] = value; } catch(e) {} } } else { // If a hook was provided get the non-computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { return ret; } // Otherwise just get the value from the style object return style[ name ]; }
// jQuery.fn.val 方法 if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } return (elem.value || "").replace(rreturn, ""); } return undefined; } //===============略============ hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; // If set returns undefined, fall back to normal setting if ( !hooks || ("set" in hooks && hooks.set( this, val, "value" ) === undefined) ) { this.value = val; }
// jQuery.attr 方法 hooks = jQuery.attrHooks[ name ] || ( jQuery.nodeName( elem, "form" ) && formHook ); if ( value !== undefined ) { if ( value === null || (value === false && !rspecial.test( name )) ) { jQuery.removeAttr( elem, name ); return undefined; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { // Set boolean attributes to the same name if ( value === true && !rspecial.test( name ) ) { value = name; } elem.setAttribute( name, "" + value ); return value; } } else { if ( hooks && "get" in hooks && notxml ) { return hooks.get( elem, name ); } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }
// jQuery.prop 方法 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 )) !== undefined ) {return ret;} else {return elem[ name ];}}
//jQuery.event.add if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } }//jQuery.event.remove if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); }
可以發現還是很有章法的。這些適配器就是用來處理一些特殊的屬性,樣式或事件。而這些屬性,樣式或事件,我們可以通過瀏覽器的特徵嗅探,把相應的解決方案添加到適配器中。有了這些適配器,jQuery就可以省去許多if else 判定,當正式版發布時,又可以高興地宣布這幾個方法快了多少百分比了!
attr = function( el, name, value ) {
// 標識是否使用寫方法
var set = value !== undefined;
if(el.nodeType == 1){
var notxml = !dom.isXML(el);
//對於HTML,我們需要對一些屬性名稱進行映射
name = notxml && dom.props[ name ] || name;
//safari 我們必須訪問上一級元素時,才能擷取這個值
if ( name === "selected" && !dom.support.optSelected ) {
var parent = el.parentNode,i = -2
while(i++ ){
parent.selectedIndex;
parent = parent.parentNode;
}
}
if (name === "style" && notxml && !dom.support.attrStyle) {
if ( set ) {
el.style.cssText = "" + value;
}
return el.style.cssText;
}
if (el[ name ] !== undefined && notxml ) {
if ( set ) {
try{
if ( value === null ) {
el.removeAttribute( name );
} else {
el[ name ] = value;
}
}catch(e){};
}
//注意formElement[name] 相等於formElement.elements[name],會返回其轄下的表單元素
if (el.tagName === "FORM" && el.getAttributeNode(name) ) {
return el.getAttributeNode( name ).nodeValue;
}
//只有能獲得焦點的元素才具有tabIndex屬性,如表單元素與指定了href的連結元素
if ( name === "tabIndex" ) {
var attributeNode = el.getAttributeNode( "tabIndex" );
return attributeNode && attributeNode.specified ?
attributeNode.value : (dom.isFormElement( el ) || el.href )?
0 : undefined;
}
if(el[name] !== el.getAttribute( name, 2 )){
return el.getAttribute( name, 2 )
}
return el[ name ];
}
if ( set ) {
el.setAttribute( name, "" + value );
}
var attr = el.getAttribute( name );
return attr === null ? undefined : attr;
}else if(el.nodeType === 9 || el.setTimeout){
if ( set ) {
el[ name ] = value;
}
return el[ name ];
}else{
return undefined;
}
}
posted on 2011-04-27 09:18 司徒正美 閱讀(...) 評論(...) 編輯 收藏