欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

細(xì)說(shuō)瀏覽器特性檢測(cè)(1)-jQuery1.4添加部分

 更新時(shí)間:2010年11月05日 22:51:19   作者:  
瀏覽器特性檢測(cè)即通過(guò)探測(cè)對(duì)象是否擁有某個(gè)屬性或者函數(shù),或者通過(guò)其他的編碼探測(cè)方式,來(lái)決定其是否支持某一功能、特性。
其最經(jīng)典的運(yùn)用莫過(guò)于通用的addEvent函數(shù):

function addEvent(element, type, handler) { 
if (element.attachEvent) { //IE8及以下瀏覽器 
element.attachEvent('on' + type, handler); 
} 
else { //W3C標(biāo)準(zhǔn)瀏覽器 
element.addEventListener(type, handler, false); 
} 
};

函數(shù)可以通過(guò)檢測(cè)attachEvent函數(shù)是否存在,以決定使用attachEvent或者addEventListener,這也是最簡(jiǎn)單的一種特性檢測(cè),因而通常在需要時(shí)才進(jìn)行實(shí)時(shí)的檢測(cè)。另一種特性檢測(cè)由于檢測(cè)的過(guò)程較為麻煩,因此會(huì)預(yù)先完成檢測(cè),將檢測(cè)的結(jié)果(通常是Boolean類(lèi)型)保存在某個(gè)變量中。

本文的主要目標(biāo)是分析、說(shuō)明在jQuery1.4中瀏覽器特性檢測(cè)新增的內(nèi)容,同時(shí)加深瀏覽器兼容性方面幾個(gè)細(xì)節(jié)的記憶。

jQuery1.4主要增加了以下幾個(gè)瀏覽器特性標(biāo)識(shí),本文針對(duì)它們一一進(jìn)行分析:

checkOn
1.4版本引入,決定沒(méi)有設(shè)置value值的checkbox是否有默認(rèn)的value值”on”。
optSelected
1.4.3版本引入,決定select元素的第一個(gè)option元素是否會(huì)默認(rèn)被選中。
optDisabled
1.4.3版本引入,決定當(dāng)select元素設(shè)置為disabled后,其所有option子元素是否也會(huì)被設(shè)置為disabled。
checkClone
1.4.1版本引入,決定對(duì)DocumentFragment使用cloneNode函數(shù)時(shí)是否會(huì)將radio和checkbox的checked屬性保留。
inlineBlockNeedsLayout
1.4.3版本引入,決定在IE下一個(gè)block元素?fù)碛衕asLayout屬性并有display: inline;時(shí),是否會(huì)按inline-block顯示。
shrinkWrapBlocks
1.4.3版本引入,決定在IE下一個(gè)元素?fù)碛衕asLayout屬性和固定的width/height時(shí),是否不會(huì)被子元素?fù)未蟆?
reliableHiddenOffsets
1.4.3版本引入,決定一個(gè)td或th元素設(shè)置為display: none;時(shí),是否還有offsetHeight。

checkOn

使用以下代碼可以檢測(cè)該特性:

<input id="checkOn" type="checkbox" /> 
<script type="text/javascript"> 
alert(document.getElementById('checkOn').value); 
</script>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 on
IE7 on
IE8 on
IE9 beta on
Firefox 3.6 on
Chrome 7 [空字符串]
Safari 5 on

經(jīng)測(cè)試,除Chrome外,所有瀏覽器都會(huì)給沒(méi)有value的checkbox一個(gè)默認(rèn)的value值”on”。

該特性被jQuery用來(lái)獲取checkbox和radio的值,兼容的判斷語(yǔ)句如下:

//不支持checkOn的瀏覽器都不存在property/attribute混用問(wèn)題,因此需要明確使用getAttribute 
return support.checkOn ? 
element.value : 
(element.getAttribute('value') === null ? 'on' : element.value);

optSelected

使用以下代碼可以檢測(cè)該特性:

<select id="optSelected"> 
</select> 
<script type="text/javascript"> 
var select = document.getElementById('optSelected'), 
option = document.createElement('option'); 
select.appendChild(option); 
alert(option.selected); 
</script>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 false
IE7 false
IE8 false
IE9 beta false
Firefox 3.6 true
Chrome 7 true
Safari 5 false

經(jīng)測(cè)試,IE系列和Safari使用appendChild對(duì)空的select元素添加一個(gè)option后,該option的selected屬性不會(huì)被默認(rèn)設(shè)置為true。

該問(wèn)題引起的BUG描述如下:

部分瀏覽器在獲取option的selected屬性時(shí),會(huì)錯(cuò)誤地返回false。

該問(wèn)題的解決方案是在訪問(wèn)selected屬性時(shí),先訪問(wèn)其父級(jí)select元素的selectedIndex屬性,強(qiáng)迫瀏覽器計(jì)算option的selected屬性,以得到正確的值。需要注意的是option元素的父元素不一定是select,也有可能是optgroup。具體代碼如下:

if (!support.optSelected) { 
var parent = option.parentNode; 
parent.selectedIndex; 
//處理optgroup時(shí)的情況 
if (parent.parentNode) { 
parent.parentNode.selectedIndex; 
} 
} 
return option.selected;

optDisabled

使用以下代碼可以檢測(cè)該特性:

<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>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 false
IE7 false
IE8 false
IE9 beta false
Firefox 3.6 false
Chrome 7 false
Safari 5 true

經(jīng)測(cè)試,Safari會(huì)將設(shè)置了disabled的select中的option也同樣設(shè)置上disabled。

這個(gè)特性用來(lái)獲取select元素的value值,特別是當(dāng)select渲染為多選框時(shí),需要注意從中去除disabled的option元素,但在Safari中,獲取被設(shè)置為disabled的select的值時(shí),由于所有option元素都被設(shè)置為disabled,會(huì)導(dǎo)致無(wú)法獲取值。

因此有optDisabled(true表示option不會(huì)被自動(dòng)設(shè)置disabled)后,可以有這樣的代碼:

//如果optDisabled為true,則disabled屬性返回的是option的真實(shí)狀態(tài) 
//否則判斷disabled屬性是否為null 
var disabled = support.optDisabled ? 
option.disabled : option.getAttribute('disabled') !== null; 
if (!disabled) { 
return option.value; 
}

checkClone

使用以下代碼可以檢測(cè)該特性:

<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>

需要注意的是,重現(xiàn)這個(gè)問(wèn)題,需要給input顯式地指定一個(gè)name屬性,并且在復(fù)制fragment對(duì)象時(shí)連續(xù)調(diào)用2次cloneNode函數(shù)。

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 true
IE7 true
IE8 true
IE9 beta true
Firefox 3.6 true
Chrome 7 true
Safari 5 true
Safari 4 false

由結(jié)果可以看出,該問(wèn)題出現(xiàn)在Safari 4中,并且已經(jīng)在Safari 5得到修復(fù),介于Safari在市場(chǎng)中的占有率以及版本較老的原因,這個(gè)問(wèn)題確實(shí)不需要太多的重視。

這個(gè)特性的使用場(chǎng)合極少,在開(kāi)發(fā)中幾乎不會(huì)有如此嚴(yán)格的環(huán)境(對(duì)DocumentFragment連續(xù)調(diào)用2次cloneNode),在jQuery中,該特性用做buildFragment這個(gè)內(nèi)部函數(shù)中的緩存功能,jQuery會(huì)對(duì)比較簡(jiǎn)單的創(chuàng)建DOM元素的字符串的創(chuàng)建結(jié)果緩存到DocumentFragment中,但當(dāng)遇到創(chuàng)建radio時(shí),如果cloneNode為false,則強(qiáng)制不進(jìn)行緩存。

inlineBlockNeedsLayout

這是一個(gè)歷史久遠(yuǎn)的問(wèn)題,IE7以下版本并不支持display: inline-block;樣式,而是使用display: inline;并通過(guò)其他樣式觸發(fā)其hasLayout形成一種偽inline-block的狀態(tài)(具體請(qǐng)點(diǎn)擊這里)。

inline-block與inline的一個(gè)重要區(qū)別在于,inline-block的元素可以顯式地設(shè)置寬和高,因此可以用以下代碼檢測(cè)該特性:

<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>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 2
IE7 2
IE8 1
IE9 beta 1
Firefox 3.6 1
Chrome 7 0
Safari 5 0

對(duì)于inline元素,width樣式是無(wú)效的,在該測(cè)試中,webkit系瀏覽器均獲取了0,IE8以上版本及Firefox獲取了1,只有IE7及以下版本同時(shí)計(jì)算了width和padding-left,得到了2px的寬度。

這個(gè)功能可以用于設(shè)置元素的css樣式,當(dāng)需要設(shè)置為inline-block時(shí),針對(duì)IE7及以下瀏覽器可以同時(shí)設(shè)置display: inline;zoom: 1;來(lái)模擬效果,核心代碼如下:

if (name == 'display' && value == 'inline-block') { 
if (support.inlineBlockNeedsLayout) { 
element.style.display = 'inline'; 
element.style.zoom = 1; 
} 
else { 
element.style.display = value; 
} 
};

當(dāng)然這樣直接這樣使用肯定是有問(wèn)題的,當(dāng)需要獲取display樣式的時(shí)候怎么辦呢?同時(shí)判斷zoom和display嗎?并且hasLayout會(huì)引起一些其他的問(wèn)題。

因此,jQuery只將該特性用于動(dòng)畫(huà)效果,當(dāng)需要對(duì)width和height進(jìn)行動(dòng)畫(huà),并且元素是inline時(shí),首先設(shè)置為(偽)inline-block狀態(tài),動(dòng)畫(huà)結(jié)束后將相關(guān)樣式恢復(fù)。

shrinkWrapBlocks

這個(gè)問(wèn)題的詳細(xì)解釋可以參考此處,使用以下代碼可以檢測(cè)該特性:

<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>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 4
IE7 1
IE8 1
IE9 beta 1
Firefox 3.6 1
Chrome 7 1
Safari 5 1

測(cè)試結(jié)果表明,IE6即使顯式設(shè)定了寬度,在觸發(fā)了hasLayout的情況下,其大小會(huì)受子元素的影響而被撐大。

jQuery將該特性用于動(dòng)畫(huà)效果,為了動(dòng)畫(huà)過(guò)程中改變一個(gè)元素的width/height時(shí),其子元素不會(huì)溢出,jQuery做了以下幾步:

  1. 保存元素當(dāng)前的overflow、overflow-x、overflow-y三個(gè)樣式。
  2. 將元素設(shè)置為inline-block以便修改width/height值。
  3. 將元素的overflow設(shè)為hidden,防止子元素溢出或當(dāng)前元素被子元素?fù)伍_(kāi)(IE6)。
  4. 在動(dòng)畫(huà)結(jié)束后,確保元素不會(huì)被子元素?fù)伍_(kāi)(shrinkWrapBlocks為true)的情況下,才恢復(fù)overflow樣式。

reliableHiddenOffsets

這個(gè)問(wèn)題在上兩天工作中遇到,剛好jQuery1.4.3升級(jí)了這方面的內(nèi)容,使用以下代碼可以檢測(cè)該特性:

<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>

以下為各瀏覽器中運(yùn)行結(jié)果:

IE6 0
IE7 0
IE8 21
IE9 beta 0
Firefox 3.6 0
Chrome 7 0
Safari 5 0

只有IE8存在這個(gè)問(wèn)題,那當(dāng)td元素的display為none時(shí),其高度依舊會(huì)受其所在行的高度的影響,而不是0。

這個(gè)問(wèn)題的存在根本上導(dǎo)致了對(duì)元素可見(jiàn)性的判定出現(xiàn)差錯(cuò),原本判斷一個(gè)元素是否隱藏的代碼是這樣的:

function isHidden(element) { 
return element.offsetWidth == 0 || element.offsetHeight == 0; 
};

因?yàn)檫@個(gè)BUG的出現(xiàn),上面的函數(shù)對(duì)于td元素失去了效果,因此需要改進(jìn)為:

function isVisible(element) { 
return (element.offsetWidth == 0 && element.offsetHeight == 0) || 
(!support.reliableHiddenOffsets && getStyle(element, 'display') == 'none'); 
};

閱讀jQuery源碼的時(shí)候,會(huì)發(fā)現(xiàn)這一段的判斷里多了一句element.style.display,這一句是用來(lái)判斷元素有display值才去取來(lái)看看是不是none的,以免獲取運(yùn)行時(shí)樣式的開(kāi)銷(xiāo)。

結(jié)語(yǔ)

  1. 特性檢測(cè)確實(shí)很有用,有時(shí)比瀏覽器版本嗅探更佳可靠,但檢測(cè)某些特性相當(dāng)麻煩,不是必要的時(shí)候不如用瀏覽器嗅探。
  2. jQuery對(duì)特性的命名真讓人想砍了他們團(tuán)隊(duì)。
  3. 有些特性可以重現(xiàn)的瀏覽器版本之低令人驚訝,在多數(shù)項(xiàng)目中完全可以不考慮,如checkClone。jQuery本身為了兼容做了太多的假設(shè),個(gè)人認(rèn)為有一些完全可以?huà)仐?,比如以后?huì)說(shuō)的getBoundingClientRect問(wèn)題。
  4. 另外還有2個(gè)關(guān)于事件上的特性檢測(cè),由于事件的特性檢測(cè)是一個(gè)通用的話(huà)題,會(huì)有今后專(zhuān)門(mén)寫(xiě)文講述,因此就不在本文中贅述了。
  5. jQuery每一個(gè)小版本的改進(jìn)都很大,特別在細(xì)節(jié)方面,這些都是要通過(guò)閱讀源碼不斷發(fā)掘的,前端的世界就是這么多變(嘆)。
  6. 本文所用的示例可以點(diǎn)此查看,具體可以查看源代碼,本文所述的各個(gè)問(wèn)題/BUG都沒(méi)在網(wǎng)上找到比較權(quán)威的說(shuō)明,還請(qǐng)見(jiàn)諒!


[Ctrl+A 全選 注:引入外部Js需再刷新一下頁(yè)面才能執(zhí)行]

相關(guān)文章

最新評(píng)論