JAVASCRIPT相容性問題
一、檢測瀏覽器的名稱
問題:
不同的瀏覽器對JavaScript的標準支援也有不同,有時希望指令碼能夠在不同的瀏覽器上都能執行良好,這時需要對瀏覽器進行檢測,確定其名稱,以針對不同的瀏覽器編寫相應的指令碼。
解決方案:
使用navigator物件的appName屬性。
比如,要檢測瀏覽器是否為IE,可以這麼做:
問題:
不同的瀏覽器對JavaScript的標準支援也有不同,有時希望指令碼能夠在不同的瀏覽器上都能執行良好,這時需要對瀏覽器進行檢測,確定其名稱,以針對不同的瀏覽器編寫相應的指令碼。
解決方案:
使用navigator物件的appName屬性。
比如,要檢測瀏覽器是否為IE,可以這麼做:
var isIE = (navigator.appName == "Microsoft Internet Explorer");
document.write("is IE?" + isIE);
document.write("is IE?" + isIE);
對於FireFox,navigator物件的appName屬性值為"Netscape";Opera9.02的appName屬性值為"Opera"(其更早版本可能不同);
二、檢測瀏覽器的版本號:
問題:
隨著瀏覽器的版本的更迭,瀏覽器所支援的指令碼特性也在變化,有時候就需要針對不同的版本編寫相應的指令碼,那麼如何獲得瀏覽器的版本號?
解決方案:
通過解析navigator物件的userAgent屬性來獲得瀏覽器的完整版本號。
IE將自己標識為MSIE,後面帶一個空格,版本號以及分號。所以我們只要取空格和分號之間的部分即可。如Windows XP SP2所帶的IE的userAgent屬性值為"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",可以看到其版本為6.0。可以用如下的函式來獲取IE瀏覽器的版本號:
function getIEVersonNumber()
{
var ua = navigator.userAgent;
var msieOffset = ua.indexOf("MSIE ");
if(msieOffset < 0)
{
return 0;
}
return parseFloat(ua.substring(msieOffset + 5, ua.indexOf(";", msieOffset)));
}
{
var ua = navigator.userAgent;
var msieOffset = ua.indexOf("MSIE ");
if(msieOffset < 0)
{
return 0;
}
return parseFloat(ua.substring(msieOffset + 5, ua.indexOf(";", msieOffset)));
}
假設我們要為IE5及以上版本編寫指令碼,可以這麼寫:
var isIE5Min = (getIEVersonNumber() >= 5);
if(isIE5Min)
{
// perform statements for IE 5 or later
}
if(isIE5Min)
{
// perform statements for IE 5 or later
}
對於FireFox和Opera等瀏覽器,也可以用navigator.userAgent屬性來獲取其版本號,只不過其形式與IE有所不同,如FireFox:
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7
Opera:Opera/9.02 (Windows NT 5.1; U; en)根據這些形式,我們不難獲得其版本號。但這些瀏覽器的其它版本沒有測試過,其具體值不明確,如果要使用這種方法檢測,請自行驗證。
下面討論下,上面的那段為IE5及以上版本瀏覽器編寫的指令碼,使用這種寫法要注意:要用>=而不是==,一般情況下,我們可以假定瀏覽器是向後相容的,所以使用==顯然不能適應新版本;另一方面,我們上面的假定也僅僅是假定,不能確保是這樣,如果瀏覽器的某些物件或屬性不能向後相容,我們的程式碼也會產生問題,所以建議,少用瀏覽器版本的比較,更多情況下,應檢測是要用的物件或屬性是否得到支援。
三、檢測客戶端的作業系統型別
根據上面的討論可以看到,navigator.userAgent屬性通常含有作業系統的基本資訊,但很不幸,沒有統一的規則去根據userAgent獲取準確的作業系統資訊,因為這些值與瀏覽器的種類、瀏覽器的版本甚至瀏覽器的OEM版本都有關係。
通常我們能做的是,檢測一些更為通用的資訊,比如作業系統是Windows還是Mac,而不是去看是Windows 98還是Windows XP。其規則是所有的Windows版本都會含有"Win",所有的Macintosh版本都含有"Mac",所有的Unix則含有"X11",而在Linux下則同時包含"X11"和"Linux"。如:
var isWin = (navigator.userAgent.indexOf("Win") != -1);
var isMac = (navigator.userAgent.indexOf("Mac") != -1);
var isUnix = (navigator.userAgent.indexOf("X11") != -1);
var isMac = (navigator.userAgent.indexOf("Mac") != -1);
var isUnix = (navigator.userAgent.indexOf("X11") != -1);
通常用在為不同的作業系統設定不同的字型或位置等樣式。
四、檢測瀏覽器對特定物件的支援
問題:
如果需要編寫對多種瀏覽器或瀏覽器的多個版本都能適用的指令碼,就要進行檢測一下,瀏覽器是否支援某個物件。當然這種檢測主要是針對那些潛在的不相容物件的語句。
解決方案:
早期的瀏覽器對於img元素的支援差別很大,所以要在指令碼中操作img元素,需要檢測瀏覽器是否支援。這時我們不需要對所有可能的瀏覽器一一檢測,只需在必要的地方用下面的方式檢測:
function rollover(imgName, imgSrc)
{
// 如果支援images物件
if(document.images)
{
// statements go here
}
}
{
// 如果支援images物件
if(document.images)
{
// statements go here
}
}
這種方法能夠生效是基於一個事實:如果document.images物件不存在,那麼if求值的結果為false。
使用這種方法,使得對物件的檢測變得簡單易行,但是我們要注意,對於那些不支援該物件的瀏覽器要如何較好得處理。看下面的程式碼:
function getImgAreas()
{
var result = 0;
for(var i = 0; i < document.images.length; i++)
{
result += (document.images[i].width * document.images[i].height);
}
return result;
}
function reportImageArea()
{
document.form1.imgData.value = getImgAreas();
}
{
var result = 0;
for(var i = 0; i < document.images.length; i++)
{
result += (document.images[i].width * document.images[i].height);
}
return result;
}
function reportImageArea()
{
document.form1.imgData.value = getImgAreas();
}
這裡沒用物件支援的檢測。如果瀏覽器支援document.images,這兩個函式執行正常;否則就會丟擲異常。下面是改進的指令碼:
function getImgAreas()
{
var result;
// 檢測瀏覽器是否支援物件
if (document.images)
{
result = 0;
for (var i = 0; i < document.images.length; i++)
{
result += (document.images[i].width * document.images[i].height);
}
}
// 返回值為一個數字或null
return result;
}
function reportImageArea()
{
// 現在可以判斷返回值
var imgArea = getImgAreas();
var output;
if (imgArea == null)
{
// 對於不支援images物件的瀏覽器也要給出相應資訊
output = "Unknown";
} else {
output = imgArea;
}
document.reportForm.imgData.value = output;
}
{
var result;
// 檢測瀏覽器是否支援物件
if (document.images)
{
result = 0;
for (var i = 0; i < document.images.length; i++)
{
result += (document.images[i].width * document.images[i].height);
}
}
// 返回值為一個數字或null
return result;
}
function reportImageArea()
{
// 現在可以判斷返回值
var imgArea = getImgAreas();
var output;
if (imgArea == null)
{
// 對於不支援images物件的瀏覽器也要給出相應資訊
output = "Unknown";
} else {
output = imgArea;
}
document.reportForm.imgData.value = output;
}
這樣,不管瀏覽器是否支援該物件,都能給使用者比較合理的資訊,而不會跳出突兀的錯誤資訊。
五、檢測瀏覽器對特定屬性和方法的支援
問題:
檢測一個物件是否含有某個特定的屬性或方法。
解決方案:
大多數情況下,可以用類似於下面的程式碼來判斷:
if(objectTest && objectPropertyTest)
{
// OK to work with property
}
{
// OK to work with property
}
先檢測物件是否存在,然後再檢測物件的屬性是否存在。如果物件確實不存在,該方法有效;如果屬性存在,但其值為null, 0, false,if語句求值的結果也將是false!所以這種方法並不安全,最好的方法是這樣:
if (objectReference && typeof(objectReference.propertyName) != "undefined")
{
// OK to work with property
}
{
// OK to work with property
}
對於方法的檢測也可用類似的方法:
function myFunction()
{
if (document.getElementById)
{
// 這裡可以使用getElementById方法
}
}
{
if (document.getElementById)
{
// 這裡可以使用getElementById方法
}
}
2----------------------
1.document.form.item 問題
(1)現有問題:
現有程式碼中存在許多 document.formName.item("itemName") 這樣的語句,不能在 MF 下執行
(2)解決方法:
改用 document.formName.elements["elementName"]
(3)其它
參見 2
2. 集合類物件問題
(1)現有問題:
現有程式碼中許多集合類物件取用時使用 (),IE 能接受,MF 不能。
(2)解決方法:
改用 [] 作為下標運算。如:document.forms("formName") 改為 document.forms["formName"]。
又如:document.getElementsByName("inputName")(1) 改為document.getElementsByName("inputName")[1]
(3)其它
3. window.event
(1)現有問題:
使用 window.event 無法在 MF 上執行
(2)解決方法:
MF 的 event 只能在事件發生的現場使用,此問題暫無法解決。可以這樣變通:
原始碼(可在IE中執行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/>
...
<script language="javascript">
function gotoSubmit() {
...
alert(window.event); // use window.event
...
}
</script>
新程式碼(可在IE和MF中執行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/>
...
<script language="javascript">
function gotoSubmit(evt) {
evt = evt ? evt : (window.event ? window.event : null);
...
alert(evt); // use evt
...
}
</script>
此外,如果新程式碼中第一行不改,與老程式碼一樣的話(即 gotoSubmit 呼叫沒有給引數),則仍然只能在IE中執行,但不會出錯。所以,這種方案 tpl 部分仍與老程式碼相容。
<script language="javascript">
function run(evnt) {
if(!document.all) {
alert(evnt.target.tagName);
}
else {
alert("IE下無法看到效果!");
}
}
</script>
<body>
<table width="200" border="1" onclick="run(event);">
<tr>
<td bgcolor="#9900CC" onClick="run(event);">1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>11</td>
<td>22</td>
<td>33</td>
</tr>
<tr onmouseover="run();">
<td>111</td>
<td>222</td>
<td>333</td>
</tr>
</table>
</body>
4. HTML 物件的 id 作為物件名的問題
(1)現有問題
在 IE 中,HTML 物件的 ID 可以作為 document 的下屬物件變數名直接使用。在 MF 中不能。
(2)解決方法
用 getElementById("idName") 代替 idName 作為物件變數使用。
5. 用idName字串取得物件的問題
(1)現有問題
在IE中,利用 eval(idName) 可以取得 id 為 idName 的 HTML 物件,在MF 中不能。
(2)解決方法
用 getElementById(idName) 代替 eval(idName)。
6. 變數名與某 HTML 物件 id 相同的問題
(1)現有問題
在 MF 中,因為物件 id 不作為 HTML 物件的名稱,所以可以使用與 HTML 物件 id 相同的變數名,IE中不能。
(2)解決方法
在宣告變數時,一律加上 var ,以避免歧義,這樣在 IE 中亦可正常執行。
此外,最好不要取與 HTML 物件 id 相同的變數名,以減少錯誤。
(3)其它
參見問題4
7. event.x 與 event.y 問題
(1)現有問題
在IE 中,event 物件有 x, y 屬性,MF中沒有。
(2)解決方法
在MF中,與event.x 等效的是 event.pageX。但event.pageX IE中沒有。
故採用 event.clientX 代替 event.x。在IE 中也有這個變數。
event.clientX 與 event.pageX 有微妙的差別(當整個頁面有滾動條的時候),不過大多數時候是等效的。
如果要完全一樣,可以稍麻煩些:
mX = event.x ? event.x : event.pageX;
然後用 mX 代替 event.x
(3)其它
event.layerX 在 IE 與 MF 中都有,具體意義有無差別尚未試驗。
8. 關於frame
(1)現有問題
在 IE中可以用window.testFrame取得該frame,mf中不行
(2)解決方法
在frame的使用方面mf和ie的最主要的區別是:
如果在frame標籤中書寫了以下屬性:
<frame src="xx.htm" id="frameId" name="frameName" />
那麼ie可以通過id或者name訪問這個frame對應的window物件
而mf只可以通過name來訪問這個frame對應的window物件
例如如果上述frame標籤寫在最上層的window裡面的htm裡面,那麼可以這樣訪問
ie: window.top.frameId或者window.top.frameName來訪問這個window物件
mf:只能這樣window.top.frameName來訪問這個window物件
另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")來訪問frame標籤
並且可以通過window.top.document.getElementById("testFrame").src = 'xx.htm'來切換frame的內容
也都可以通過window.top.frameName.location = 'xx.htm'來切換frame的內容
關於frame和window的描述可以參見bbs的‘window與frame’文章
以及/test/js/test_frame/目錄下面的測試
----adun 2004.12.09修改
9. 在mf中,自己定義的屬性必須getAttribute()取得
10.在mf中沒有 parentElement parement.children 而用
parentNode parentNode.childNodes
childNodes的下標的含義在IE和MF中不同,MF使用DOM規範,childNodes中會插入空白文字節點。
一般可以通過node.getElementsByTagName()來回避這個問題。
當html中節點缺失時,IE和MF對parentNode的解釋不同,例如
<form>
<table>
<input/>
</table>
</form>
MF中input.parentNode的值為form, 而IE中input.parentNode的值為空節點
MF中節點沒有removeNode方法,必須使用如下方法 node.parentNode.removeChild(node)
11.const 問題
(1)現有問題:
在 IE 中不能使用 const 關鍵字。如 const constVar = 32; 在IE中這是語法錯誤。
(2)解決方法:
不使用 const ,以 var 代替。
12. body 物件
MF的body在body標籤沒有被瀏覽器完全讀入之前就存在,而IE則必須在body完全被讀入之後才存在
13. url encoding
在js中如果書寫url就直接寫&不要寫&例如var url = 'xx.jsp?objectName=xx&objectEvent=xxx';
frm.action = url那麼很有可能url不會被正常顯示以至於引數沒有正確的傳到伺服器
一般會伺服器報錯引數沒有找到
當然如果是在tpl中例外,因為tpl中符合xml規範,要求&書寫為&
一般MF無法識別js中的&
14. nodeName 和 tagName 問題
(1)現有問題:
在MF中,所有節點均有 nodeName 值,但 textNode 沒有 tagName 值。在 IE 中,nodeName 的使用好象
有問題(具體情況沒有測試,但我的IE已經死了好幾次)。
(2)解決方法:
使用 tagName,但應檢測其是否為空。
15. 元素屬性
IE下 input.type屬性為只讀,但是MF下可以修改
16. document.getElementsByName() 和 document.all[name] 的問題
(1)現有問題:
在 IE 中,getElementsByName()、document.all[name] 均不能用來取得 div 元素(是否還有其它不能取的元素還不知道)。
(1)現有問題:
現有程式碼中存在許多 document.formName.item("itemName") 這樣的語句,不能在 MF 下執行
(2)解決方法:
改用 document.formName.elements["elementName"]
(3)其它
參見 2
2. 集合類物件問題
(1)現有問題:
現有程式碼中許多集合類物件取用時使用 (),IE 能接受,MF 不能。
(2)解決方法:
改用 [] 作為下標運算。如:document.forms("formName") 改為 document.forms["formName"]。
又如:document.getElementsByName("inputName")(1) 改為document.getElementsByName("inputName")[1]
(3)其它
3. window.event
(1)現有問題:
使用 window.event 無法在 MF 上執行
(2)解決方法:
MF 的 event 只能在事件發生的現場使用,此問題暫無法解決。可以這樣變通:
原始碼(可在IE中執行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/>
...
<script language="javascript">
function gotoSubmit() {
...
alert(window.event); // use window.event
...
}
</script>
新程式碼(可在IE和MF中執行):
<input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/>
...
<script language="javascript">
function gotoSubmit(evt) {
evt = evt ? evt : (window.event ? window.event : null);
...
alert(evt); // use evt
...
}
</script>
此外,如果新程式碼中第一行不改,與老程式碼一樣的話(即 gotoSubmit 呼叫沒有給引數),則仍然只能在IE中執行,但不會出錯。所以,這種方案 tpl 部分仍與老程式碼相容。
<script language="javascript">
function run(evnt) {
if(!document.all) {
alert(evnt.target.tagName);
}
else {
alert("IE下無法看到效果!");
}
}
</script>
<body>
<table width="200" border="1" onclick="run(event);">
<tr>
<td bgcolor="#9900CC" onClick="run(event);">1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>11</td>
<td>22</td>
<td>33</td>
</tr>
<tr onmouseover="run();">
<td>111</td>
<td>222</td>
<td>333</td>
</tr>
</table>
</body>
4. HTML 物件的 id 作為物件名的問題
(1)現有問題
在 IE 中,HTML 物件的 ID 可以作為 document 的下屬物件變數名直接使用。在 MF 中不能。
(2)解決方法
用 getElementById("idName") 代替 idName 作為物件變數使用。
5. 用idName字串取得物件的問題
(1)現有問題
在IE中,利用 eval(idName) 可以取得 id 為 idName 的 HTML 物件,在MF 中不能。
(2)解決方法
用 getElementById(idName) 代替 eval(idName)。
6. 變數名與某 HTML 物件 id 相同的問題
(1)現有問題
在 MF 中,因為物件 id 不作為 HTML 物件的名稱,所以可以使用與 HTML 物件 id 相同的變數名,IE中不能。
(2)解決方法
在宣告變數時,一律加上 var ,以避免歧義,這樣在 IE 中亦可正常執行。
此外,最好不要取與 HTML 物件 id 相同的變數名,以減少錯誤。
(3)其它
參見問題4
7. event.x 與 event.y 問題
(1)現有問題
在IE 中,event 物件有 x, y 屬性,MF中沒有。
(2)解決方法
在MF中,與event.x 等效的是 event.pageX。但event.pageX IE中沒有。
故採用 event.clientX 代替 event.x。在IE 中也有這個變數。
event.clientX 與 event.pageX 有微妙的差別(當整個頁面有滾動條的時候),不過大多數時候是等效的。
如果要完全一樣,可以稍麻煩些:
mX = event.x ? event.x : event.pageX;
然後用 mX 代替 event.x
(3)其它
event.layerX 在 IE 與 MF 中都有,具體意義有無差別尚未試驗。
8. 關於frame
(1)現有問題
在 IE中可以用window.testFrame取得該frame,mf中不行
(2)解決方法
在frame的使用方面mf和ie的最主要的區別是:
如果在frame標籤中書寫了以下屬性:
<frame src="xx.htm" id="frameId" name="frameName" />
那麼ie可以通過id或者name訪問這個frame對應的window物件
而mf只可以通過name來訪問這個frame對應的window物件
例如如果上述frame標籤寫在最上層的window裡面的htm裡面,那麼可以這樣訪問
ie: window.top.frameId或者window.top.frameName來訪問這個window物件
mf:只能這樣window.top.frameName來訪問這個window物件
另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")來訪問frame標籤
並且可以通過window.top.document.getElementById("testFrame").src = 'xx.htm'來切換frame的內容
也都可以通過window.top.frameName.location = 'xx.htm'來切換frame的內容
關於frame和window的描述可以參見bbs的‘window與frame’文章
以及/test/js/test_frame/目錄下面的測試
----adun 2004.12.09修改
9. 在mf中,自己定義的屬性必須getAttribute()取得
10.在mf中沒有 parentElement parement.children 而用
parentNode parentNode.childNodes
childNodes的下標的含義在IE和MF中不同,MF使用DOM規範,childNodes中會插入空白文字節點。
一般可以通過node.getElementsByTagName()來回避這個問題。
當html中節點缺失時,IE和MF對parentNode的解釋不同,例如
<form>
<table>
<input/>
</table>
</form>
MF中input.parentNode的值為form, 而IE中input.parentNode的值為空節點
MF中節點沒有removeNode方法,必須使用如下方法 node.parentNode.removeChild(node)
11.const 問題
(1)現有問題:
在 IE 中不能使用 const 關鍵字。如 const constVar = 32; 在IE中這是語法錯誤。
(2)解決方法:
不使用 const ,以 var 代替。
12. body 物件
MF的body在body標籤沒有被瀏覽器完全讀入之前就存在,而IE則必須在body完全被讀入之後才存在
13. url encoding
在js中如果書寫url就直接寫&不要寫&例如var url = 'xx.jsp?objectName=xx&objectEvent=xxx';
frm.action = url那麼很有可能url不會被正常顯示以至於引數沒有正確的傳到伺服器
一般會伺服器報錯引數沒有找到
當然如果是在tpl中例外,因為tpl中符合xml規範,要求&書寫為&
一般MF無法識別js中的&
14. nodeName 和 tagName 問題
(1)現有問題:
在MF中,所有節點均有 nodeName 值,但 textNode 沒有 tagName 值。在 IE 中,nodeName 的使用好象
有問題(具體情況沒有測試,但我的IE已經死了好幾次)。
(2)解決方法:
使用 tagName,但應檢測其是否為空。
15. 元素屬性
IE下 input.type屬性為只讀,但是MF下可以修改
16. document.getElementsByName() 和 document.all[name] 的問題
(1)現有問題:
在 IE 中,getElementsByName()、document.all[name] 均不能用來取得 div 元素(是否還有其它不能取的元素還不知道)。
第一:onload
網頁載入完執行的函式,這個程式碼是從十大常用javascript的函式裡面摘取的,當然有其他的實現方法,但這個函式寫的真的非常巧妙。從效率方面也是一個非常值得使用的函式!
以下就是具體程式碼:
//--------------------------------------------------------
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
}
else {
window.onload = function() {
oldonload();
func();
}
}
}
//--------------------------------------------------------
我不想一句一句的分析這個addLoadEvent,那是高手們很難接受的!我們就來說說它的相容性!請看函式中window.onload,作者為什麼不用document.body.onload呢?那是因為在Firefox[以下全部簡稱ff]下document.body.onload是undefined(未定義),把一個函式賦值給undefined既不會發生什麼事情,也不算出錯!這個是讓人頭痛!好的,知道相容性的厲害了吧?那麼,以後在編寫程式碼時注意一下就好了!
第二:body
這個body物件也是困擾我們的東西,叫它物件不知道對不對?我不是學計算機專業的,專業術語還真不大清楚!
以下就是具體程式碼:
//--------------------------------------------------------
function getPageScroll(){
var yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
}
// Explorer 6 Strict
else if (document.documentElement && document.documentElement.scrollTop){
yScroll = document.documentElement.scrollTop;
} else if (document.body) {// all other Explorers
yScroll = document.body.scrollTop;
}
arrayPageScroll = new Array('',yScroll)
return arrayPageScroll;
}
//--------------------------------------------------------
這個函式作用是:瀏覽器滾動條滾動的高度讀取。這是從lightbox中摘錄的,讀讀這段程式碼,看到三次判斷:
1.if (self.pageYOffset)對ff進行判斷處理;
2.if (document.documentElement && document.documentElement.scrollTop)是對網頁標準(xHTML 1.1 DTD)的判斷,這裡要說明一下:在加入 xHTML 1.1 DTD 檔案頭時document.body.scrollTop之類的值往往是0,而這個是很難被除錯察覺的(我曾因此困惑很久,這裡吐血傳授經驗啦!);
3.則是我們常用document.body.scrollTop。
從這三次判斷,可以想象作者思維的嚴密了!當然這是程式設計師的共性!
第三:attachEvent/addEventListener
這裡是比較直接的區別,可是太多的直接卻造成了程式設計的困擾,這不禁使人想起:到底有多少這樣的直接不同函式?他們的差別到底在哪裡?畢竟大家的大腦空間有限,這麼多怎麼記?可是這些是必須記住的!沒事,這篇文章裡常見的js相容性都提到了,可以作為“家居旅行,隨身攜帶”的小手冊!
以下就是具體程式碼:
//--------------------------------------------------------
_observeAndCache: function(element, name, observer, useCapture) {
if (!this.observers) this.observers = [];
if (element.addEventListener) {
this.observers.push([element, name, observer, useCapture]);
element.addEventListener(name, observer, useCapture);
} else if (element.attachEvent) {
this.observers.push([element, name, observer, useCapture]);
element.attachEvent('on' + name, observer);
}
}
//--------------------------------------------------------
意思是給物件新增事件。這是Sam Stephenson的prototype中類的一部分,舉這段程式碼,不是讓你去慢慢分析那個prototype.js檔案,只是說明在ie和Opera下就可以使用obj.attachEvent(),但在ff下卻只能使用obj.addEventListener()。
類似區別的還有:
detachEvent/removeEventListener
parentElement/parentNode
insertAdjacentElement/appendChild
srcElement/target
onmousewheel/DOMMouseScroll
clientY/pageY
第四:物件引用
1.getElementById
請看以下程式碼:
<!-- 1 -->
<input id="t1"><input type="button"
value="click me" onclick="alert(t1.value)">
<!-- 2 -->
<input id="t1"><input type="button"
value="click me" onclick="alert(document.getElementById('t1').value)">
兩個都是獲取文字框的值,但後者的相容性就比前者好!對於IE來說,一個HTML 元素的ID可以直接在指令碼中當作變數名來使用,而ff中不可以。
getElementById這個函式是非常有用、通用的函式,所以在引用物件時我們要儘量使用它!
2.var
請看以下程式碼:
//--------------------------------------------------------
echo=function(str){
document.write(str);
}
//--------------------------------------------------------
這個函式在ie上執行正常,ff下卻報錯了,而在echo前加上var就正常了,這個就是我們提到var的目的。
3.[]
document.forms(”formName”) 改為 document.forms[”formName”]目的:現有程式碼中許多集合類物件取用時使用 (),ie 能接受,ff 卻不能。
4.frame的引用
ie可以通過id或者name訪問這個frame對應的window物件,而mf只可以通過name來訪問這個frame對應的window物件。
第五:指令碼執行
讓我們分別做個試驗,請出ie和ff分別執行一下下面一段js:
//--------------------------------------------------------
o={
foo: function(){
alert("fly");
}
};
with (o) {
bar();
function bar(){
alert("fly");
}
foo();
}
//--------------------------------------------------------
IE下,上面的程式碼成功輸出fly,ff報錯:bar未定義!
當然這是一個小小的試驗,大家很明顯的看出ie和ff的支援執行的情況:ie指令碼預解釋執行,ff指令碼順序執行!這是javascript編寫和設計時必須注意的東西!
第六:XMLHttpRequest物件
請看以下程式碼
//--------------------------------------------------------
function createRequest(){
if(typeof XMLHttpRequest!="undefined")? {
return new XMLHttpRequest();
}else if(typeof ActiveXObject!="undefined"){
var xmlHttp_ver? = false;
var xmlHttp_vers = [
"MSXML2.XmlHttp.5.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp",
"Microsoft.XmlHttp"
];
if(!xmlHttp_ver){
for(var i=0;i<xmlHttp_vers.length;i++){
try{
new ActiveXObject(xmlHttp_vers[i]);
xmlHttp_ver = xmlHttp_vers[i];
break;
}catch(oError){;}
}
}
if(xmlHttp_ver){
return new ActiveXObject(xmlHttp_ver);
}else{
throw new Error("Could not create XML HTTP Request.");
}
}else{
throw new Error("Your browser doesn't support an XML HTTP Request.");
}
}
//--------------------------------------------------------
意思是:得到XMLHttpRequest物件,是喜悅村裡的一個兄弟寫的。在ie下,一句new ActiveXObject("MSXML2.XMLHTTP")就可以搞定的東西,但這裡我們花了這麼多行程式碼來解決相容性問題,這個函式作者更從原理入手:xmlHttp_vers 應該從版本高的往版本低的寫,這樣建立物件的資料呼叫的是你機子上安裝過的最高版本的MSXML2.XmlHttp。十分巧妙和有效地得到了物件!
好了,其實關於javascript相容性的例子還有很多,我們無法羅列所有,這裡做了個簡單介紹,更多的只能在程式設計工程中去慢慢體會了!當然本文僅僅討論了js的相容性,同時css的相容性問題也是不可忽視的!解決相容性最好的方法就是封裝!
網頁載入完執行的函式,這個程式碼是從十大常用javascript的函式裡面摘取的,當然有其他的實現方法,但這個函式寫的真的非常巧妙。從效率方面也是一個非常值得使用的函式!
以下就是具體程式碼:
//--------------------------------------------------------
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
}
else {
window.onload = function() {
oldonload();
func();
}
}
}
//--------------------------------------------------------
我不想一句一句的分析這個addLoadEvent,那是高手們很難接受的!我們就來說說它的相容性!請看函式中window.onload,作者為什麼不用document.body.onload呢?那是因為在Firefox[以下全部簡稱ff]下document.body.onload是undefined(未定義),把一個函式賦值給undefined既不會發生什麼事情,也不算出錯!這個是讓人頭痛!好的,知道相容性的厲害了吧?那麼,以後在編寫程式碼時注意一下就好了!
第二:body
這個body物件也是困擾我們的東西,叫它物件不知道對不對?我不是學計算機專業的,專業術語還真不大清楚!
以下就是具體程式碼:
//--------------------------------------------------------
function getPageScroll(){
var yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
}
// Explorer 6 Strict
else if (document.documentElement && document.documentElement.scrollTop){
yScroll = document.documentElement.scrollTop;
} else if (document.body) {// all other Explorers
yScroll = document.body.scrollTop;
}
arrayPageScroll = new Array('',yScroll)
return arrayPageScroll;
}
//--------------------------------------------------------
這個函式作用是:瀏覽器滾動條滾動的高度讀取。這是從lightbox中摘錄的,讀讀這段程式碼,看到三次判斷:
1.if (self.pageYOffset)對ff進行判斷處理;
2.if (document.documentElement && document.documentElement.scrollTop)是對網頁標準(xHTML 1.1 DTD)的判斷,這裡要說明一下:在加入 xHTML 1.1 DTD 檔案頭時document.body.scrollTop之類的值往往是0,而這個是很難被除錯察覺的(我曾因此困惑很久,這裡吐血傳授經驗啦!);
3.則是我們常用document.body.scrollTop。
從這三次判斷,可以想象作者思維的嚴密了!當然這是程式設計師的共性!
第三:attachEvent/addEventListener
這裡是比較直接的區別,可是太多的直接卻造成了程式設計的困擾,這不禁使人想起:到底有多少這樣的直接不同函式?他們的差別到底在哪裡?畢竟大家的大腦空間有限,這麼多怎麼記?可是這些是必須記住的!沒事,這篇文章裡常見的js相容性都提到了,可以作為“家居旅行,隨身攜帶”的小手冊!
以下就是具體程式碼:
//--------------------------------------------------------
_observeAndCache: function(element, name, observer, useCapture) {
if (!this.observers) this.observers = [];
if (element.addEventListener) {
this.observers.push([element, name, observer, useCapture]);
element.addEventListener(name, observer, useCapture);
} else if (element.attachEvent) {
this.observers.push([element, name, observer, useCapture]);
element.attachEvent('on' + name, observer);
}
}
//--------------------------------------------------------
意思是給物件新增事件。這是Sam Stephenson的prototype中類的一部分,舉這段程式碼,不是讓你去慢慢分析那個prototype.js檔案,只是說明在ie和Opera下就可以使用obj.attachEvent(),但在ff下卻只能使用obj.addEventListener()。
類似區別的還有:
detachEvent/removeEventListener
parentElement/parentNode
insertAdjacentElement/appendChild
srcElement/target
onmousewheel/DOMMouseScroll
clientY/pageY
第四:物件引用
1.getElementById
請看以下程式碼:
<!-- 1 -->
<input id="t1"><input type="button"
value="click me" onclick="alert(t1.value)">
<!-- 2 -->
<input id="t1"><input type="button"
value="click me" onclick="alert(document.getElementById('t1').value)">
兩個都是獲取文字框的值,但後者的相容性就比前者好!對於IE來說,一個HTML 元素的ID可以直接在指令碼中當作變數名來使用,而ff中不可以。
getElementById這個函式是非常有用、通用的函式,所以在引用物件時我們要儘量使用它!
2.var
請看以下程式碼:
//--------------------------------------------------------
echo=function(str){
document.write(str);
}
//--------------------------------------------------------
這個函式在ie上執行正常,ff下卻報錯了,而在echo前加上var就正常了,這個就是我們提到var的目的。
3.[]
document.forms(”formName”) 改為 document.forms[”formName”]目的:現有程式碼中許多集合類物件取用時使用 (),ie 能接受,ff 卻不能。
4.frame的引用
ie可以通過id或者name訪問這個frame對應的window物件,而mf只可以通過name來訪問這個frame對應的window物件。
第五:指令碼執行
讓我們分別做個試驗,請出ie和ff分別執行一下下面一段js:
//--------------------------------------------------------
o={
foo: function(){
alert("fly");
}
};
with (o) {
bar();
function bar(){
alert("fly");
}
foo();
}
//--------------------------------------------------------
IE下,上面的程式碼成功輸出fly,ff報錯:bar未定義!
當然這是一個小小的試驗,大家很明顯的看出ie和ff的支援執行的情況:ie指令碼預解釋執行,ff指令碼順序執行!這是javascript編寫和設計時必須注意的東西!
第六:XMLHttpRequest物件
請看以下程式碼
//--------------------------------------------------------
function createRequest(){
if(typeof XMLHttpRequest!="undefined")? {
return new XMLHttpRequest();
}else if(typeof ActiveXObject!="undefined"){
var xmlHttp_ver? = false;
var xmlHttp_vers = [
"MSXML2.XmlHttp.5.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp",
"Microsoft.XmlHttp"
];
if(!xmlHttp_ver){
for(var i=0;i<xmlHttp_vers.length;i++){
try{
new ActiveXObject(xmlHttp_vers[i]);
xmlHttp_ver = xmlHttp_vers[i];
break;
}catch(oError){;}
}
}
if(xmlHttp_ver){
return new ActiveXObject(xmlHttp_ver);
}else{
throw new Error("Could not create XML HTTP Request.");
}
}else{
throw new Error("Your browser doesn't support an XML HTTP Request.");
}
}
//--------------------------------------------------------
意思是:得到XMLHttpRequest物件,是喜悅村裡的一個兄弟寫的。在ie下,一句new ActiveXObject("MSXML2.XMLHTTP")就可以搞定的東西,但這裡我們花了這麼多行程式碼來解決相容性問題,這個函式作者更從原理入手:xmlHttp_vers 應該從版本高的往版本低的寫,這樣建立物件的資料呼叫的是你機子上安裝過的最高版本的MSXML2.XmlHttp。十分巧妙和有效地得到了物件!
好了,其實關於javascript相容性的例子還有很多,我們無法羅列所有,這裡做了個簡單介紹,更多的只能在程式設計工程中去慢慢體會了!當然本文僅僅討論了js的相容性,同時css的相容性問題也是不可忽視的!解決相容性最好的方法就是封裝!
3----瀏覽器相容性
JavaScript程式設計的最大問題來自不同的瀏覽器對各種技術和標準的支援。構建一個執行在不同瀏覽器(如IE和火狐)是一個困難的任務。因此幾種AJAX JavaScript框架或者生成基於服務端邏輯或標記庫的JavaScript,或者提供符合跨瀏覽器AJAX開發的客戶端JavaScript庫。一些流行的框架包括:AJAX.Net, Backbase, Bitkraft, Django, DOJO, DWR, MochiKit, Prototype, Rico, Sajax, Sarissa, and
Script.aculo.us.
這些框架給開發人員更多的空間使得他們不需要擔心跨瀏覽器的問題。雖然這些框架提升了開發人員構建應用的能力,但由於廠商已經開發了更細節的使用者介面的打包元件解決方案,因此在AJAX元件市場中需要考慮一些其他因素。例如提供通用使用者介面的元件如組合框和資料柵格的幾個廠商,都可以被用來在應用中建立良好的通過類似電子資料表方式來檢視和編輯資料的體驗。但這些元件不僅是封裝了元件的使用者介面而且包括與服務端資料的通訊方式,這些元件通常使用基於標記方式來實現如ASP.Net或JSF控制元件。
這些框架給開發人員更多的空間使得他們不需要擔心跨瀏覽器的問題。雖然這些框架提升了開發人員構建應用的能力,但由於廠商已經開發了更細節的使用者介面的打包元件解決方案,因此在AJAX元件市場中需要考慮一些其他因素。例如提供通用使用者介面的元件如組合框和資料柵格的幾個廠商,都可以被用來在應用中建立良好的通過類似電子資料表方式來檢視和編輯資料的體驗。但這些元件不僅是封裝了元件的使用者介面而且包括與服務端資料的通訊方式,這些元件通常使用基於標記方式來實現如ASP.Net或JSF控制元件。
Ajax在本質上是一個瀏覽器端的技術,首先面臨無可避免的第一個問題即是瀏覽器的相容性問題。各家瀏覽器對於JavaScript/DOM/CSS的支援總有部分不太相同或是有Bug,甚至同一瀏覽器的各個版本間對於JavaScript/DOM/CSS的支援也有可能部分不一樣。這導致程式設計師在寫Ajax應用時花大部分的時間在除錯瀏覽器的相容性而非在應用程式本身。因此,目前大部分的Ajax連結庫或開發框架大多以js連結庫的形式存在,以定義更高階的JavaScript
API、JavaScript物件(模板)、或者JavaScript Widgets來解決此問題。如prototype.js
相關文章
- Go mod 相容性問題Go
- input file相容性問題
- 關於火狐和IE下href=”javascript:void(0)”相容性的問題JavaScript
- 解決ie相容性問題
- 常見的相容性問題
- 移動端相容性問題
- 前端相容性問題總結前端
- 初識onkeydown及其相容性問題
- [轉帖]Podman與docker相容性問題Docker
- web頁面相容性問題記錄Web
- Python-geopandas-fiona相容性問題-20241209Python
- Docker與銀河麒麟的相容性問題Docker
- 解決django 2.2與mysql相容性問題DjangoMySql
- JavaScript中this指向問題JavaScript
- javascript的this指向問題JavaScript
- 微信小程式中的iOS相容性問題微信小程式iOS
- 移動端相容性問題解決方案(一)
- angular瀏覽器相容性問題解決方案Angular瀏覽器
- css背景漸變相容性問題(非原創)CSS
- 智慧硬體相容性測試常見問題
- 各大瀏覽器滾動條相容性問題瀏覽器
- webpack 中版本相容性問題錯誤總結Web
- 移動端常見相容性問題解決方案
- 如何機智地回答瀏覽器相容性問題瀏覽器
- CUDA常見驅動程式相容性問題一覽
- 主流瀏覽器相容性問題與解決方案瀏覽器
- JavaScript中揹包問題(面試題)JavaScript面試題
- 你遇到過的相容性問題以及解決辦法
- ios手機處理keyup事件時的相容性問題iOS事件
- Android 9 Pie 相容性常見問題及注意事項Android
- 移動端Android跟ios相容性問題,反人類!!!AndroidiOS
- javascript中的各種問題JavaScript
- 關於javascript的this指向問題JavaScript
- JavaScript中有關new的問題JavaScript
- eventlet 之 monkeypatch 帶來的若干相容性問題例項分析
- 移動 web 開發幾個明顯的相容性問題Web
- 記一次移動端使用 rem 的相容性問題REM
- PC端/移動端常見的相容性問題總結
- 利用 JavaScript Profiler 分析 Vue 效能問題JavaScriptVue