jQuery 源码分析笔记(5) jQuery.support


Posted in Javascript onJune 19, 2011

其中jQuery.browser已经提供了根据UserAgent检测的浏览器信息。而jQuery.support 使用特性检测来检查浏览器的功能以及Bug。

和文档一样,首先说明一下,这个模块是很底层的代码,基本不需要在日常开发中使用,但是插件的开发者更需要。因为插件需要兼容各个浏览器。首先看一下 support模块提供了哪些浏览器特性的检测,以下结果是在Chrome 13 Dev下看到的结果。根据浏览器的不同,这里的成员可能会有变化。(PS:再次吐槽IE,大部分属性都是IE比较特别)

  • ajax: true。是否支持XMLHttpRequest对象。老版本的IE不支持,必须用ActiveX。 * appendChecked: true。 * boxModel: true。是否根据W3C CSS盒模式渲染。IE6和7的Quirks模式为False。 * changeBubbles: true。change事件是否沿着DOM树冒泡。这是W3C DOM事件模型的要求,但是IE目前为止是False。jQuery模拟了这个冒泡特性。 * checkClone: undefined。在克隆Radio Button或者CheckBox时是否保留选中状态。以前说createFragment缓存的时候提到过,WebKit内核是不保留的。 * checkOn: false。CheckBox在没有指定时是否默认为On。 * cors: true。XMLHttpRequest对象是否带有withCredentials属性。可以执行跨域请求。或者没有这个属性,但是有其他途径可以实现跨域XHR请求的,也是True(比如通过Windows Gadget)。 * cssFloat: true。支持cssFloat的CSS属性。IE是False,它使用了styleFloat。 * deleteExpando: true。 * focusinBubbles: false。 * getSetAttribute: true。 * hrefNormalized: true。对一个a元素调用getAttribute("href")时,是否返回原始指定的URL。IE会返回完整路径。比如对于href="1.html"的链接,IE会得到http://..../1.html。 * htmlSerialize: true。是否可以用innerHTML插入link元素。IE为false。 * inlineBlockNeedsLayout: false。为了让block元素表现inline-block,是否需要为inline并且hasLayout(IE下的概念,大部分布局问题的根源)。IE8以下有问题。 * leadingWhitespace: true。innerHTML属性是否严格按照代码渲染。IE6-8中会去掉前置的空白。(所以使用Markdown写的这篇文章在IE下有格式问题,因为换行不见了) * noCloneChecked: true。1.5.1新属性。检测浏览器是否克隆checked扩展属性。IE为false。 * noCloneEvent: true。拷贝的元素是否会带有事件处理函数(即Event handler是否被拷贝过去)。IE为false。 * opacity: true。是否支持opacity CSS属性(透明度)。IE为false,它使用alpha filter。 * optDisabled: true。已经disabled的select元素中的option元素是否默认为disabled。 * optSelected: true。一个默认被选中的option元素的selected属性是否正常。 * radioValue: true。 * reliableHiddenOffsets: true。在table的cells被设置为display:none的时候,仍然有offsetWidth/Height。即hidden靠不住。只有IE8有这个问题。参见4512号bug * reliableMarginRight: true。div有显式的宽度,但是没有margin-right。此时基于容器计算margin-right不正确。旧版本WebKit有问题。参见3333号bug * scriptEval(): 1.5.1版本前,这是一个属性,而现在变成函数了。检测一个inline的脚本在使用标准的DOM操作函数被添加时是否会自动执行。比如appendChild和createTextNode。IE是false,它使用text来插入脚本。 * shrinkWrapBlocks: false。元素在hasLayout的情况下是否会撑大父节点。只有IE6是true。 * style: true。一个元素的inline的style属性是否可以用DOM属性访问。比如getAttribute("style")。IE是false,它使用cssText属性。 * submitBubbles: true。submit事件是否沿着DOM树冒泡。IE为false,jQuery模拟了这个冒泡过程。 * tbody: true。一个空的table元素是否可以没有tbody元素。根据HTML规范,子元素是可选的。但是IE是false,所以会自动插入一个tbody元素。

jQuery创建了几个元素用来判断浏览器特性。如下:

var div = document.createElement("div"); 
div.setAttribute("className", "t"); 
div.innerHTML = " <LINK><TABLE><TBODY></TBODY></TABLE><A style="FLOAT: left; TOP: 1px; opacity: .55" href="https://3water.com/a">a</A><INPUT type=checkbox>"; 
all = div.getElementsByTagName("*"); 
a = div.getElementsByTagName("a")[0]; 
var select = document.createElement("select"); 
opt = select.appendChild(document.createElement("option")); 
input = div.getElementsByTagName("input")[0];

其中div元素相当有内涵。包括了空白开头,空Table元素,inline style,opacity等等。除了一行行看代码和注释也没啥其他笔记了:
support = { 
// IE会把开头的空格去掉,所以nodeType不是3(文本) 
leadingWhitespace: (div.firstChild.nodeType === 3), 
// IE会自动插入tbody,所以length不同 
tbody: !div.getElementsByName("tbody").length, 
// IE不允许用这种方式插入link元素 
htmlSerialize: !!div.getElementsByTagName("link").length, 
// 如果正常获得style的话,这个正则表达式应该会正常通过 
style: /top/.test(a.getAttribute("style")), 
// href属性应该是原始指定的字符串,IE会修改为http开头的绝对URL 
hrefNormalized: (a.getAttribute("href") === "/a"), 
// 能得到opacity属性。这里使用了正则表达式,是为了绕过WebKit[5145号bug](http://dev.jquery.com/ticket/5145) 
// 但是这应该是一个早期版本的问题。起码在Chrome 13中,不用正则也是对的。 
opacity: /^0.55$/.test(a.style.opacity), 
// IE使用styleFloat 
cssFloat: !!a.style.cssFloat, 
// div中的checkbox没有指定值,看默认值是否是on。WebKit是""。所以我的结果是false 
checkOn: (input.value === "on"), 
// 这个select只有一个option元素,所以渲染时,这个option是默认选中的。此时selected应该是true。 
optSelected: opt.selected, 
submitBubbles: true, 
changeBubbles: true, 
focusinBubbles: false, 
deleteExpando: true, 
noCloneEvent: true, 
inlineBlockNeedsLayout: false, 
shrinkWrapBlocks: false, 
reliableMarginRight: true 
};

下面的大部分都是按部就班的测试。其中BoxModel的测试比较有趣:
div.innerHTML = ""; // 从头来 
div.style.width = div.style.paddingLeft = "1px"; 
body = document.createElement("body"); 
body.style.width = 0; 
body.style.height = 0; 
body.style.border = 0; 
body.style.margin = 0; // 全部设置为0 
body.appendChild(div); 
document.documentElement.insertBefore(body, document.documentElement.firstChild); 
support.boxModel = div.offsetWidth === 2; 
// 这个时候div嵌套在body下。而body长宽高,边框和margin都是0。所以div的偏移应该就是它自己的paddingLeft+width。如果不对,就说明盒模式不对。

然后值得注意的是事件的冒泡,注释中提到的技术参考文章链接已经失效。请自己搜索"Detecting event support without browser sniffing"
// attachEvent是IE的,所以这里实际上只检查了IE,其他浏览器都是前面设置的默认值。 
if(div.attachEvent) { 
for(i = { 
submit: 1, 
change: 1 
focusin: 1 
}) { 
eventName = "on" + i; 
isSupported = (eventName in div); 
if(!isSupported) { 
div.setAttribute(eventName, "return;"); 
isSupported = (typeof div[eventName] === "function"); 
} 
support[i + "Bubbles"] = isSupported; 
} 
}

PS: 浏览器检测是一个很纠结,很细节的任务。这个笔记慢慢完善中……

18:30补充:经过IE9的测试,以上大部分IE相关问题都已经不存在。以下是IE9+Win7的测试结果:

$.support 
{ 
boxModel: true, 
changeBubbles: true, 
checkClone: true, 
checkOn: true, 
cssFloat: true, 
deleteExpando: true, 
hrefNormalized: true, 
htmlSerialize: true, 
leadingWhitespace: true, 
noCloneEvent: false, 
opacity: true, 
optSelected: false, 
parentNode: true, 
scriptEval: true, 
style: true, 
submitBubbles: true, 
tbody: true 
}
Javascript 相关文章推荐
用AJAX返回HTML片段中的JavaScript脚本
Jan 04 Javascript
JavaScript常用全局属性与方法记录积累
Jul 03 Javascript
JavaScript怎么判断图片是否加载完成以便获取其尺寸
May 08 Javascript
jQuery遍历对象、数组、集合实例
Nov 08 Javascript
HTML中setCapture、releaseCapture 使用方法浅析
Sep 25 Javascript
BootStrap中关于Select下拉框选择触发事件及扩展
Nov 22 Javascript
JavaScript 中的 this 简单规则
Sep 19 Javascript
vue中使用element-ui进行表单验证的实例代码
Jun 22 Javascript
微信小程序实现炫酷的弹出式菜单特效
Jan 28 Javascript
微信小程序实现搜索历史功能
Mar 26 Javascript
Vue项目中数据的深度监听或对象属性的监听实例
Jul 17 Javascript
使用Vue.js和MJML创建响应式电子邮件
Mar 23 Vue.js
jQuery调用WebService的实现代码
Jun 19 #Javascript
非常棒的10款jQuery 幻灯片插件
Jun 14 #Javascript
在jquery中处理带有命名空间的XML数据
Jun 13 #Javascript
jquery 与NVelocity 产生冲突的解决方法
Jun 13 #Javascript
用Juery网页选项卡实现代码
Jun 13 #Javascript
读jQuery之三(构建选择器)
Jun 11 #Javascript
读jQuery之二(两种扩展)
Jun 11 #Javascript
You might like
PHP新手上路(三)
2006/10/09 PHP
PHP strtotime函数详解
2009/12/18 PHP
服务器web工具 php环境下
2010/12/29 PHP
使用NetBeans + Xdebug调试PHP程序的方法
2011/04/12 PHP
PHP查找数值数组中不重复最大和最小的10个数的方法
2015/04/20 PHP
php的mail函数发送UTF-8编码中文邮件时标题乱码的解决办法
2015/10/20 PHP
php实现的错误处理封装类实例
2017/06/20 PHP
redis+php实现微博(二)发布与关注功能详解
2019/09/23 PHP
javascript hashtable实现代码
2009/10/13 Javascript
JavaScript Event学习第七章 事件属性
2010/02/07 Javascript
仿猪八戒网左下角的文字滚动效果
2011/10/28 Javascript
js 去掉空格实例 Trim() LTrim() RTrim()
2014/01/07 Javascript
JS访问SWF的函数用法实例
2015/07/01 Javascript
jquery easyui dataGrid动态改变排序字段名的方法
2017/03/02 Javascript
C#微信小程序服务端获取用户解密信息实例代码
2017/03/10 Javascript
JavaScript中递归实现的方法及其区别
2017/09/12 Javascript
JS实现自定义状态栏动画文字效果示例
2017/10/12 Javascript
详解ES6中的代理模式——Proxy
2018/01/08 Javascript
vue.js实现只弹一次弹框
2018/01/29 Javascript
通过实例了解js函数中参数的传递
2019/06/15 Javascript
一起写一个即插即用的Vue Loading插件实现
2019/10/31 Javascript
JS实现手写 forEach算法示例
2020/04/29 Javascript
JS+CSS实现动态时钟
2021/02/19 Javascript
[38:21]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS Newbee
2018/03/31 DOTA
Python获取数据库数据并保存在excel表格中的方法
2019/06/12 Python
python爬虫用mongodb的理由
2020/07/28 Python
Python 虚拟环境工作原理解析
2020/12/24 Python
css3选择器基本介绍
2014/12/15 HTML / CSS
澳大利亚最好的在线时尚精品店:Princess Polly
2018/01/03 全球购物
数据库基础的一些面试题
2012/02/25 面试题
食品工程专业求职信
2014/06/15 职场文书
基层党员干部四风问题整改方向和措施
2014/09/25 职场文书
仓库管理员岗位职责
2015/02/03 职场文书
2015年双拥工作总结
2015/04/08 职场文书
交通事故代理词范文
2015/05/23 职场文书
redis 存储对象的方法对比分析
2021/08/02 Redis