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 相关文章推荐
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(下:动画篇)
Mar 24 Javascript
ExtJS Ext.MessageBox.alert()弹出对话框详解
Apr 02 Javascript
深入分析js中的constructor和prototype
Apr 07 Javascript
表头固定(利用jquery实现原理介绍)
Nov 08 Javascript
jQuery遍历json的方法分析
Apr 16 Javascript
利用jqprint插件打印页面内容的实现方法
Jan 09 Javascript
vue.js提交按钮时进行简单的if判断表达式详解
Aug 08 Javascript
详解微信小程序实现跑马灯效果(附完整代码)
Apr 29 Javascript
vue项目前端知识点整理【收藏】
May 13 Javascript
如何在Node和浏览器控制台中打印彩色文字
Jan 09 Javascript
JavaScript实现指定数量的并发限制的示例代码
Mar 10 Javascript
JavaScript实现优先级队列
Dec 06 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执行sql语句的写法
2009/03/10 PHP
ThinkPHP3.2.2的插件控制器功能
2015/03/05 PHP
PHP使用mysql与mysqli连接Mysql数据库用法示例
2016/07/07 PHP
Laravel统计一段时间间隔的数据方法
2019/10/09 PHP
Prototype Hash对象 学习
2009/07/19 Javascript
动态的创建一个元素createElement及删除一个元素
2014/01/24 Javascript
JavaScript数组各种常见用法实例分析
2015/08/04 Javascript
js立即执行函数: (function ( ){})( ) 与 (function ( ){}( )) 有什么区别?
2015/11/18 Javascript
jquery判断类型是不是number类型的实例代码
2016/10/07 Javascript
angular2倒计时组件使用详解
2017/01/12 Javascript
AngularJS的ng-repeat指令与scope继承关系实例详解
2017/01/21 Javascript
通过示例彻底搞懂js闭包
2017/08/10 Javascript
Vue keep-alive实践总结(推荐)
2017/08/31 Javascript
Vue-Router模式和钩子的用法
2018/02/28 Javascript
angularJs利用$scope处理升降序的方法
2018/10/08 Javascript
layer弹出子iframe层父子页面传值的实现方法
2018/11/22 Javascript
原生JS实现的放大镜特效示例【测试可用】
2018/12/08 Javascript
js实现鼠标点击飘爱心效果
2020/08/19 Javascript
javaScript代码飘红报错看不懂?读完这篇文章再试试
2020/08/19 Javascript
Python的Tornado框架异步编程入门实例
2015/04/24 Python
Python实现的生产者、消费者问题完整实例
2018/05/30 Python
python实现可逆简单的加密算法
2019/03/22 Python
python的Jenkins接口调用方式
2020/05/12 Python
使用phonegap播放音频的实现方法
2017/03/31 HTML / CSS
web字体加载方案优化小结
2019/11/29 HTML / CSS
VICHY薇姿俄罗斯官方网上商店:法国护肤品牌,火山温泉水
2019/11/22 全球购物
线程的基本概念、线程的基本状态以及状态之间的关系
2012/10/26 面试题
介绍一下Ruby的特点
2013/01/20 面试题
顺丰快递Java软件工程师面试题
2015/07/31 面试题
汽车专业学生自我评价
2014/01/19 职场文书
《大海那边》教学反思
2014/04/09 职场文书
2014年销售人员工作总结
2014/11/27 职场文书
幼儿教师年度个人总结
2015/02/05 职场文书
新课程改革心得体会
2016/01/22 职场文书
python爬虫框架feapde的使用简介
2021/04/20 Python
JavaScript控制台的更多功能
2021/04/28 Javascript