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 相关文章推荐
js实现的网站首页随机公告随机公告
Mar 14 Javascript
javascripit实现密码强度检测代码分享
Dec 12 Javascript
js实现连个数字相加而不是拼接的方法
Feb 23 Javascript
在Linux上用forever实现Node.js项目自启动
Jul 09 Javascript
javascript实现单击和双击并存的方法
Dec 13 Javascript
js确认框confirm()用法实例详解
Jan 07 Javascript
jQuery 实现评论等级好评差评特效
May 06 Javascript
浅谈Node.js:理解stream
Dec 08 Javascript
AngularJS实现的回到顶部指令功能实例
May 17 Javascript
Vuejs2 + Webpack框架里,模拟下载的实例讲解
Sep 05 Javascript
VUE实现Studio管理后台之鼠标拖放改变窗口大小
Mar 04 Javascript
layui使用及简单的三级联动实现教程
Dec 01 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程序的国际化实现方法(利用gettext)
2011/08/14 PHP
ajax在joomla中的原生态应用代码
2012/07/19 PHP
解析php中array_merge与array+array的区别
2013/06/21 PHP
PHP中使用Imagick实现各种图片效果实例
2015/01/21 PHP
PHP的Socket网络编程入门指引
2015/08/11 PHP
简介WordPress中用于获取首页和站点链接的PHP函数
2015/12/17 PHP
利用PHPExcel读取Excel的数据和导出数据到Excel
2017/05/12 PHP
JavaScript 字符串与数组转换函数[不用split与join]
2009/12/13 Javascript
新发现一个骗链接的方法(js读取cookies)
2012/01/11 Javascript
jtable列中自定义button示例代码
2013/11/21 Javascript
JS实现网页表格自动变大缩小的方法
2015/03/09 Javascript
基于Vue.js的表格分页组件
2016/05/22 Javascript
微信小程序 wx:key详细介绍
2016/10/28 Javascript
livereload工具实现前端可视化开发【推荐】
2016/12/23 Javascript
详解关于Vue版本不匹配问题(Vue packages version mismatch)
2018/09/17 Javascript
node事件循环和process模块实例分析
2020/02/14 Javascript
纯JS实现五子棋游戏
2020/05/28 Javascript
Python写的PHPMyAdmin暴力破解工具代码
2014/08/06 Python
Python实现遍历数据库并获取key的值
2015/05/17 Python
Python get获取页面cookie代码实例
2018/09/12 Python
python pandas时序处理相关功能详解
2019/07/03 Python
Python多版本开发环境管理工具介绍
2019/07/03 Python
django-crontab 定时执行任务方法的实现
2019/09/06 Python
Python Web静态服务器非堵塞模式实现方法示例
2019/11/21 Python
安装pyecharts1.8.0版本后导入pyecharts模块绘图时报错: “所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 ”的解决方法
2020/08/18 Python
解决TensorFlow训练模型及保存数量限制的问题
2021/03/03 Python
唤醒头发毛囊的秘密武器:Grow Gorgeous
2016/08/28 全球购物
美体小铺加拿大官方网站:The Body Shop加拿大
2016/10/30 全球购物
介绍一下grep命令的使用
2015/06/12 面试题
国庆节文艺活动方案
2014/02/03 职场文书
《蝙蝠和雷达》教学反思
2014/04/23 职场文书
2014年党员自我评议(5篇)
2014/09/12 职场文书
中学生社区服务活动报告
2015/02/05 职场文书
回复函范文
2015/07/14 职场文书
python 逐步回归算法
2021/04/06 Python
JavaScript 防篡改对象的用法示例
2021/04/24 Javascript