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 相关文章推荐
为javascript添加String.Format方法
Aug 11 Javascript
JQuery Easyui Tree的oncheck事件实现代码
May 28 Javascript
Jvascript学习实践案例(开发常用)
Jun 25 Javascript
javascript中常用编程知识
Apr 08 Javascript
浅谈Javascript如何实现匀速运动
Dec 19 Javascript
推荐4个原生javascript常用的函数
Jan 12 Javascript
整理Javascript流程控制语句学习笔记
Nov 29 Javascript
jQuery多文件异步上传带进度条实例代码
Aug 16 Javascript
ReactNative页面跳转实例代码
Sep 27 Javascript
JQ中$(window).load和$(document).ready区别与执行顺序
Mar 01 Javascript
简单实现js上传文件功能
Aug 21 Javascript
前端开发之便利店收银系统代码
Dec 27 Javascript
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代码包装修正版
2008/03/15 PHP
php获得用户ip地址的比较不错的方法
2014/02/08 PHP
PHP封装的XML简单操作类完整实例
2017/11/13 PHP
免费空间广告万能消除代码
2006/09/04 Javascript
不错的asp中显示新闻的功能
2006/10/13 Javascript
js带按钮的提示框可供选择示例代码
2013/09/17 Javascript
Eclipse下jQuery文件报错出现错误提示红叉
2014/01/13 Javascript
JS(JQuery)操作Array的相关方法介绍
2014/02/11 Javascript
javascript中的this详解
2014/12/08 Javascript
javascript用函数实现对象的方法
2015/05/14 Javascript
javascript字符串函数汇总
2015/12/06 Javascript
Vue.js使用v-show和v-if的注意事项
2016/12/13 Javascript
javascript实现简单打字游戏
2019/10/29 Javascript
js实现div色块拖动录制
2020/01/16 Javascript
python操作MySQL 模拟简单银行转账操作
2017/09/27 Python
Python对Excel按列值筛选并拆分表格到多个文件的代码
2019/11/05 Python
python读取hdfs上的parquet文件方式
2020/06/06 Python
Python高并发解决方案实现过程详解
2020/07/31 Python
如何解决pycharm调试报错的问题
2020/08/06 Python
Python Merge函数原理及用法解析
2020/09/16 Python
使用 css3 transform 属性来变换背景图的方法
2019/05/07 HTML / CSS
html5 利用canvas手写签名并保存的实现方法
2018/07/12 HTML / CSS
html5 桌面提醒:Notifycations应用介绍
2012/11/27 HTML / CSS
捷克钓鱼用品网上商店:Parys.cz
2018/06/15 全球购物
苹果台湾官网:Apple台湾
2019/01/05 全球购物
屈臣氏乌克兰:Watsons UA
2019/10/29 全球购物
西安众合通用.net笔试题
2013/03/18 面试题
法学专业自我鉴定
2014/02/05 职场文书
实习协议书范本
2014/04/22 职场文书
活动总结报告格式
2014/05/09 职场文书
法院授权委托书格式
2014/09/28 职场文书
群众路线自我剖析及整改措施
2014/11/04 职场文书
pytorch 使用半精度模型部署的操作
2021/05/24 Python
SpringBoot实现异步事件驱动的方法
2021/06/28 Java/Android
java中用float时,数字后面加f,这样是为什么你知道吗
2021/09/04 Java/Android
「SHOW BY ROCK!!」“雫シークレットマインド”组合单曲MV公开
2022/03/21 日漫