jquery的hooks兼容之input兼容处理讲解
2017-03-10 00:56

jQuery的attr的hooks对input的兼容处理

jQuery之attr源码解析中,我们讲解了jquery对于attr方法的兼容,通过hooks方式的架构方式进行兼容处理,这种兼容方式有很好的可扩展性,很值得我们学习,今天我们就对具体的attr的hooks的兼容处理之一:input属性兼容,进行源码分析。

hooks只input的兼容源码

我们先上源码

attrHooks: {
	type: {
		set: function( elem, value ) {
			// We can't allow the type property to be changed(since it causes problems in IE)
			if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
				jQuery.error( "type property can't be changed" );
			}else 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 it's default in case type is set after value
			    // This is for element creation
			    var val = elem.value;
			    elem.setAttribute( "type", value );
			    if ( val ) {
				elem.value = val;
			    }
				return value;
			}
		}
	},
	// Use the value property for back compat
	// Use the nodeHook for button elements in IE6/7 (#1954)
	value: {
		get: function( elem, name ) {
			if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
				return nodeHook.get( elem, name );
			}
			return name in elem ?
				elem.value :
				null;
		},
		set: function( elem, value, name ) {
			if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
				return nodeHook.set( elem, value, name );
			}
			// Does not return so that setAttribute is also used
			elem.value = value;
		}
	}
},

首先,type包含set的兼容处理:

type: {
	set: function( elem, value ) {
	// We can't allow the type property to be changed (since it causes problems in IE)
		if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
			jQuery.error( "type property can't be changed" );
		} else 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 it's default in case type is set after value
			// This is for element creation
			var val = elem.value;
			elem.setAttribute( "type", value );
			if ( val ) {
				elem.value = val;
			}
				return value;
			}
		}
	}
rtype = /^(?:button|input)$/i,
jQuery.extend({
    nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
	}
});
input = document.createElement("input");
input.value = "t";
input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";

第一句“rtype.test(elem.nodeName)&&parentNode”,这句话表示的意思是什么呢?“rtype”是上面的正则,表示标签名是“input”或者“button”,parentNode代表元素的父元素,什么元素有父元素呢,中文档中的元素有父元素,通过“document.createElement('input')”创建的元素没有父元素。

这个判断就是说,如果是文档中的input元素要修改type类型,那么对不起,由于IE的原因,jquery不支持。

而下面的else if中的判断又代表什么呢?

这个support.radioValue在chrome,Firfox浏览器下为true,在IE浏览器下为false;这个为什么IE6-9下为什么会是false呢,jquery给出了注释,因为做IE6-9下面,

"radio"元素创建过程中,需要先设置“type”类型,后设置“value”,如果先设置“value”,后设置“type”,那么在设置“type”的时候,会重置为默认的“on”值。而jquery采取的input的创建方式是先设置“value”后设置“type”的,所以要做这个处理,也可以说这个兼容性是jquery自个搞出来的。

if里面的代码就好理解了,就是先保存value值,然后设置type,之后再恢复value值。在这个版本中attr("type","radio")只是jquery内部使用创建元素的功能。

上面的源码摘自1.8.3版本的jquery,

而在jquery高版本(我看的是 1.9.1版本)中的type兼容代码如下:

attrHooks: {
	type: {
		set: function( elem, value ) {
			if ( !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中去除了对是否是文档中元素修改“type”的判断,反正对于IE浏览器,你修改type都会报错,干脆去除那些个多余的判断,反倒能使chrome,friefox等浏览器可以修改type类型。这个改进是很有必要的,因为我们现在很多系统页面有时候会不考虑IE浏览器,jquery这一改进,是不能因为IE得安全限制策略而抛弃了其他浏览器的可用功能。

type属性这有set的兼容,get获取,走的还是“getAttribute”或者“getAttributeNode”常规方法来获取属性值。

下面我们再看看value属性的兼容代码

// Use the value property for back compat
// Use the nodeHook for button elements in IE6/7 (#1954)
value: {
	get: function( elem, name ) {
		if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
			return nodeHook.get( elem, name );
		}
		return name in elem ?
			elem.value :
			null;
		},
	set: function( elem, value, name ) {
		if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
			return nodeHook.set( elem, value, name );
		}
		// Does not return so that setAttribute is also used
			elem.value = value;
		}
}

这里提一点,你可以细看前文中对于attr方法的源码解析,hooks方法如果返回的是undefined,那么他会继续调用通过的“getAttribute”,"setAttribute"等方法处理。

value属性有两个兼容方法“get”和“set”。先看get方法

get: function( elem, name ) {
	if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
		return nodeHook.get( elem, name );
	}
		return name in elem ?
			elem.value :
			null;
    },
if ( !getSetAttribute ) {

	fixSpecified = {
		name: true,
		id: true,
		coords: true
	};
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = jQuery.valHooks.button = {
	get: function( elem, name ) {
		var ret;
		ret = elem.getAttributeNode( name );
		return ret && ( fixSpecified[ name ] ? ret.value !== "" : ret.specified ) ?
			ret.value :
			undefined;
	},
	set: function( elem, value, name ) {
		// Set the existing or create a new attribute node
		var ret = elem.getAttributeNode( name );
		if ( !ret ) {
			ret = document.createAttribute( name );
			elem.setAttributeNode( ret );
		}
		return ( ret.value = value + "" );
	}
};
}
div = document.createElement("div");

// Setup
div.setAttribute( "className", "t" );
getSetAttribute: div.className !== "t",

get方法中,先判断nodeHook是否是undefined,如果不是undefined,那么就调用nodeHook的get方法获取value属性。

nodeHook是什么呢,通过判断setAttribute能否添加属性成功来判断setAttribute的可用性,IE6-7虽然也有setAttribute方法,但是调用无效,需要使用setAttributeNode方法来设置属性。nodeHook就是通过setAttributeNode方法设置属性,通过getAttributeNode获取属性的。

nodeHook中的get方法判断属性节点不为空并且是“name”,“id”,"coords"属性之一或者属性节点值不为空字符串时返回属性节点值,否则返回undefined。

非IE6-7浏览器下,value属性的get方法返回属性值或者null。对于自定义属性返回null会促使调用“getAttribute”方法来获取属性值。

set: function( elem, value, name ) {
	if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
		return nodeHook.set( elem, value, name );
	}
	// Does not return so that setAttribute is also used
		elem.value = value;
	}

value的set方法和get方法的逻辑是一样的,在非IE6-7浏览器下通过“elem.value=value”不设置返回值,促使调用“setAttribute”来设置自定义属性。

总结

本文讲解的jquery的hooks中的type和value兼容处理的东西不多,type就是处理radio的赋值先后在IE下的问题,并且主要是jquery内部创建爱元素使用,value兼容也是兼容IE6-7下的setAttribute,getAttribute不起作用的问题。

希望通过对jquery源码的分析,能让你掌握更多浏览器兼容性的知识,虽然IE有时我们不再考虑,但是大部分情况下,IE还是占很大份额的,毕竟是随系统安装的浏览器,用户不再少量,再加之各种国产浏览器,都是IE和webkit的双内核浏览器,IE的兼容在PC端就更不能弃之不理了。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(1104)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1