function addEvent(element, type, handler) {
if (element.attachEvent) { //IE8及以下浏览器
element.attachEvent('on' + type, handler);
}
else { //W3C标准浏览器
element.addEventListener(type, handler, false);
}
};
函数可以通过检测attachEvent函数是否存在,以决定使用attachEvent或者addEventListener,这也是最简单的一种特性检测,因而通常在需要时才进行实时的检测。另一种特性检测由于检测的过程较为麻烦,因此会预先完成检测,将检测的结果(通常是Boolean类型)保存在某个变量中。
本文的主要目标是分析、说明在jQuery1.4中浏览器特性检测新增的内容,同时加深浏览器兼容性方面几个细节的记忆。
jQuery1.4主要增加了以下几个浏览器特性标识,本文针对它们一一进行分析:
- checkOn
- 1.4版本引入,决定没有设置value值的checkbox是否有默认的value值”on”。
- optSelected
- 1.4.3版本引入,决定select元素的第一个option元素是否会默认被选中。
- optDisabled
- 1.4.3版本引入,决定当select元素设置为disabled后,其所有option子元素是否也会被设置为disabled。
- checkClone
- 1.4.1版本引入,决定对DocumentFragment使用cloneNode函数时是否会将radio和checkbox的checked属性保留。
- inlineBlockNeedsLayout
- 1.4.3版本引入,决定在IE下一个block元素拥有hasLayout属性并有
display: inline;
时,是否会按inline-block显示。 - shrinkWrapBlocks
- 1.4.3版本引入,决定在IE下一个元素拥有hasLayout属性和固定的width/height时,是否不会被子元素撑大。
- reliableHiddenOffsets
- 1.4.3版本引入,决定一个td或th元素设置为
display: none;
时,是否还有offsetHeight。
checkOn
使用以下代码可以检测该特性:
<input id="checkOn" type="checkbox" />
<script type="text/javascript">
alert(document.getElementById('checkOn').value);
</script>
以下为各浏览器中运行结果:
IE6 on IE7 on IE8 on IE9 beta on Firefox 3.6 on Chrome 7 [空字符串] Safari 5 on经测试,除Chrome外,所有浏览器都会给没有value的checkbox一个默认的value值”on”。
该特性被jQuery用来获取checkbox和radio的值,兼容的判断语句如下:
//不支持checkOn的浏览器都不存在property/attribute混用问题,因此需要明确使用getAttribute
return support.checkOn ?
element.value :
(element.getAttribute('value') === null ? 'on' : element.value);
optSelected
使用以下代码可以检测该特性:
<select id="optSelected">
</select>
<script type="text/javascript">
var select = document.getElementById('optSelected'),
option = document.createElement('option');
select.appendChild(option);
alert(option.selected);
</script>
以下为各浏览器中运行结果:
IE6 false IE7 false IE8 false IE9 beta false Firefox 3.6 true Chrome 7 true Safari 5 false经测试,IE系列和Safari使用appendChild对空的select元素添加一个option后,该option的selected属性不会被默认设置为true。
该问题引起的BUG描述如下:
部分浏览器在获取option的selected属性时,会错误地返回false。
该问题的解决方案是在访问selected属性时,先访问其父级select元素的selectedIndex属性,强迫浏览器计算option的selected属性,以得到正确的值。需要注意的是option元素的父元素不一定是select,也有可能是optgroup。具体代码如下:
if (!support.optSelected) {
var parent = option.parentNode;
parent.selectedIndex;
//处理optgroup时的情况
if (parent.parentNode) {
parent.parentNode.selectedIndex;
}
}
return option.selected;
optDisabled
使用以下代码可以检测该特性:
<select id="optDisabled" disabled="disabled">
<option></option>
</select>
<script type="text/javascript">
var select = document.getElementById('optDisabled'),
option = select.getElementsByTagName('option')[0];
alert(option.disabled);
</script>
以下为各浏览器中运行结果:
IE6 false IE7 false IE8 false IE9 beta false Firefox 3.6 false Chrome 7 false Safari 5 true经测试,Safari会将设置了disabled的select中的option也同样设置上disabled。
这个特性用来获取select元素的value值,特别是当select渲染为多选框时,需要注意从中去除disabled的option元素,但在Safari中,获取被设置为disabled的select的值时,由于所有option元素都被设置为disabled,会导致无法获取值。
因此有optDisabled(true表示option不会被自动设置disabled)后,可以有这样的代码:
//如果optDisabled为true,则disabled属性返回的是option的真实状态
//否则判断disabled属性是否为null
var disabled = support.optDisabled ?
option.disabled : option.getAttribute('disabled') !== null;
if (!disabled) {
return option.value;
}
checkClone
使用以下代码可以检测该特性:
<div id="checkClone">
<input type="radio" name="checkClone" checked="checked" />
</div>
<script type="text/javascript">
var fragment = document.createDocumentFragment(),
div = document.getElementById('checkClone'),
radio = div.getElementsByTagName('input')[0];
fragment.appendChild( radio );
alert(fragment.cloneNode(true).cloneNode(true).lastChild.checked);
</script>
需要注意的是,重现这个问题,需要给input显式地指定一个name属性,并且在复制fragment对象时连续调用2次cloneNode函数。
以下为各浏览器中运行结果:
IE6 true IE7 true IE8 true IE9 beta true Firefox 3.6 true Chrome 7 true Safari 5 true Safari 4 false由结果可以看出,该问题出现在Safari 4中,并且已经在Safari 5得到修复,介于Safari在市场中的占有率以及版本较老的原因,这个问题确实不需要太多的重视。
这个特性的使用场合极少,在开发中几乎不会有如此严格的环境(对DocumentFragment连续调用2次cloneNode),在jQuery中,该特性用做buildFragment这个内部函数中的缓存功能,jQuery会对比较简单的创建DOM元素的字符串的创建结果缓存到DocumentFragment中,但当遇到创建radio时,如果cloneNode为false,则强制不进行缓存。
inlineBlockNeedsLayout
这是一个历史久远的问题,IE7以下版本并不支持display: inline-block;
样式,而是使用display: inline;
并通过其他样式触发其hasLayout形成一种伪inline-block的状态(具体请点击这里)。
inline-block与inline的一个重要区别在于,inline-block的元素可以显式地设置宽和高,因此可以用以下代码检测该特性:
<div id="inlineBlockNeedsLayout" style="width: 1px; padding-left: 1px; display: inline;
zoom: 1;">
</div>
<script type="text/javascript">
var div = document.getElementById('inlineBlockNeedsLayout');
alert(div.offsetWidth);
</script>
以下为各浏览器中运行结果:
IE6 2 IE7 2 IE8 1 IE9 beta 1 Firefox 3.6 1 Chrome 7 0 Safari 5 0对于inline元素,width样式是无效的,在该测试中,webkit系浏览器均获取了0,IE8以上版本及Firefox获取了1,只有IE7及以下版本同时计算了width和padding-left,得到了2px的宽度。
这个功能可以用于设置元素的css样式,当需要设置为inline-block时,针对IE7及以下浏览器可以同时设置display: inline;
和zoom: 1;
来模拟效果,核心代码如下:
if (name == 'display' && value == 'inline-block') {
if (support.inlineBlockNeedsLayout) {
element.style.display = 'inline';
element.style.zoom = 1;
}
else {
element.style.display = value;
}
};
当然这样直接这样使用肯定是有问题的,当需要获取display样式的时候怎么办呢?同时判断zoom和display吗?并且hasLayout会引起一些其他的问题。
因此,jQuery只将该特性用于动画效果,当需要对width和height进行动画,并且元素是inline时,首先设置为(伪)inline-block状态,动画结束后将相关样式恢复。
shrinkWrapBlocks
这个问题的详细解释可以参考此处,使用以下代码可以检测该特性:
<div id="shrinkWrapBlocks" style="width: 1px; zoom: 1;">
<div style="width: 4px;">
</div>
</div>
<script type="text/javascript">
var div = document.getElementById('shrinkWrapBlocks'),
inner = div.getElementsByTagName('div')[0];
alert(div.offsetWidth);
</script>
以下为各浏览器中运行结果:
IE6 4 IE7 1 IE8 1 IE9 beta 1 Firefox 3.6 1 Chrome 7 1 Safari 5 1测试结果表明,IE6即使显式设定了宽度,在触发了hasLayout的情况下,其大小会受子元素的影响而被撑大。
jQuery将该特性用于动画效果,为了动画过程中改变一个元素的width/height时,其子元素不会溢出,jQuery做了以下几步:
- 保存元素当前的overflow、overflow-x、overflow-y三个样式。
- 将元素设置为inline-block以便修改width/height值。
- 将元素的overflow设为hidden,防止子元素溢出或当前元素被子元素撑开(IE6)。
- 在动画结束后,确保元素不会被子元素撑开(shrinkWrapBlocks为true)的情况下,才恢复overflow样式。
reliableHiddenOffsets
这个问题在上两天工作中遇到,刚好jQuery1.4.3升级了这方面的内容,使用以下代码可以检测该特性:
<table id="reliableHiddenOffsets">
<tbody>
<tr>
<td style="display: none;">
</td>
<td>
abcd
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
var table = document.getElementById('reliableHiddenOffsets'),
td = table.getElementsByTagName('td')[0];
alert(td.offsetHeight);
</script>
以下为各浏览器中运行结果:
IE6 0 IE7 0 IE8 21 IE9 beta 0 Firefox 3.6 0 Chrome 7 0 Safari 5 0只有IE8存在这个问题,那当td元素的display为none时,其高度依旧会受其所在行的高度的影响,而不是0。
这个问题的存在根本上导致了对元素可见性的判定出现差错,原本判断一个元素是否隐藏的代码是这样的:
function isHidden(element) {
return element.offsetWidth == 0 || element.offsetHeight == 0;
};
因为这个BUG的出现,上面的函数对于td元素失去了效果,因此需要改进为:
function isVisible(element) {
return (element.offsetWidth == 0 && element.offsetHeight == 0) ||
(!support.reliableHiddenOffsets && getStyle(element, 'display') == 'none');
};
阅读jQuery源码的时候,会发现这一段的判断里多了一句element.style.display
,这一句是用来判断元素有display值才去取来看看是不是none的,以免获取运行时样式的开销。
结语
- 特性检测确实很有用,有时比浏览器版本嗅探更佳可靠,但检测某些特性相当麻烦,不是必要的时候不如用浏览器嗅探。
- jQuery对特性的命名真让人想砍了他们团队。
- 有些特性可以重现的浏览器版本之低令人惊讶,在多数项目中完全可以不考虑,如checkClone。jQuery本身为了兼容做了太多的假设,个人认为有一些完全可以抛弃,比如以后会说的getBoundingClientRect问题。
- 另外还有2个关于事件上的特性检测,由于事件的特性检测是一个通用的话题,会有今后专门写文讲述,因此就不在本文中赘述了。
- jQuery每一个小版本的改进都很大,特别在细节方面,这些都是要通过阅读源码不断发掘的,前端的世界就是这么多变(叹)。
- 本文所用的示例可以点此查看,具体可以查看源代码,本文所述的各个问题/BUG都没在网上找到比较权威的说明,还请见谅!
[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
浏览器,特性检测
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】