IE版本向下相容所遇到的問題(基本上以IE9為分水嶺)
之前幫客戶開發一個小專案,給使用者測試也都沒問題
正式上線之後,才有使用者反應程式無法正常執行
當下猜想是瀏覽器版本的問題
經過測試之後,程式碼降到IE8時就開始出錯了
只是客戶不知道為何無法給我使用者的瀏覽器版本
所以姑且就先向下相容到IE8
以下記錄遇到的問題
一、Array
1.沒有indexOf和lastIndexOf
IE9之前沒有indexOf和lastIndexOf這兩個方法,若要使用的話必須要自己對底層新增方法
網路上可以查到很多寫法,以下為我所使用的方法
indexOf:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (elt /*, from*/) {
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++) {
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
更簡短的版本為
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
lastIndexOf:
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
'use strict';
if (this === void 0 || this === null) {
throw new TypeError();
}
var n, k,
t = Object(this),
len = t.length >>> 0;
if (len === 0) {
return -1;
}
n = len - 1;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) {
n = 0;
}
else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
for (k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n); k >= 0; k--) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
};
}
2.沒有forEach,
IE9以前的Array沒有forEach訪問元素的方法,所以一樣可以自己加在底層,而專案裡我選擇改用jquery的$.each方法。
若要在底層新增方法,以下是我找到的範例:
if (typeof Array.prototype.forEach != 'function') {
Array.prototype.forEach = function(callback){
for (var i = 0; i < this.length; i++){
callback.apply(this, [this[i], i, this]);
}
};
}
二、Date
1.Date沒有toISOString()
Date中的toISOString方法,會回傳國際標準日期字串(ISO8601),其格式為(YYYY-MM-DDTHH:mm:ss.sssZ)
而IE9之前不支援此方法,所以若想要得到相同的效果要人工拼湊,或者在底層增加方法,其程式碼為:
if ( !Date.prototype.toISOString ) {
(function() {
function pad(number) {
var r = String(number);
if ( r.length === 1 ) {
r = '0' + r;
}
return r;
}
Date.prototype.toISOString = function() {
return this.getUTCFullYear()
+ '-' + pad( this.getUTCMonth() + 1 )
+ '-' + pad( this.getUTCDate() )
+ 'T' + pad( this.getUTCHours() )
+ ':' + pad( this.getUTCMinutes() )
+ ':' + pad( this.getUTCSeconds() )
+ '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
+ 'Z';
}
}() );
}
2.Date.parse
IE9之前的版本若要解析時間字串,只接受2020/12/31這樣有斜線的格式
而其他格式的時間字串會回傳NaN
所以在傳入字串之前最好用replace替換一下其他常見的表示方法,如2020.12.31或2020-12-31等
三、input的file
1.取得input的file檔案
IE10之前要取得input的file裡的檔案很麻煩,其麻煩的點為IE10之前沒有FormData,要到IE10才開始支援。
而如果是直接傳送表單(submit form)的話還好,但大部分的應用都是搭配Ajax傳送檔案,而想要用Ajax就勢必要先取得檔案。
第一個要注意的是,IE版本不同其檔案所在的子節點也會不同,所以以下的範例是根據不同的版本做出不同的應對:
var getUploadForm;
var file;
if (navigator.appName == "Microsoft Internet Explorer"
&& navigator.appVersion.split(";")[1].replace(/[ ]/g, "") == "MSIE8.0") {
getUploadForm = evtTarget.parentNode.children[0];
file = getUploadForm.children[0].value;
} else {
getUploadForm = evtTarget.parentNode.children[1];
file = getUploadForm.children[0].files[0];
}
2.取得檔案內容
在上面的程式碼中,我順便取得了檔案資訊,IE8之前取得的方法也從files[i]改成value。
且IE10之前的file只有取得路徑名,不會有其他屬性可以使用,所以如果想要判斷檔名或格式之類的,必須使用以下的程式碼先取得檔名+副檔名:
(註:前面為IE10之後的寫法,後面是IE10之前的寫法)
var fileName = file.name || file.substring(file.lastIndexOf('\\') + 1);
3.上傳檔案
既然沒有FormData可以使用,那就只好借助jquery.form的力量啦。
其使用方法大同小異,差別在於用serialize()將檔案序列化,並用ajaxSubmit送出請求,以下為程式碼範例:
<script src="~/Scripts/jquery-1.12.4.js"></script>
<script src="~/Scripts/jquery.form.js"></script>
Var formData = $(getUploadForm).serialize(); //延續上面的程式碼
$(getUploadForm).ajaxSubmit({
url: '@Url.Action("UploadFile", "Home")',
type: "POST",
data: formData,
success: function (data) {
//以下省略……
}
})
四、其他
1.關鍵字delete
原本我將物件中的某個方法命名為delete,原本能正常執行,但降版後就出現錯誤。
經查詢資料後,發現delete是javascript的keyword,其用途是刪除某個物件的某個屬性,所以其實本來就不應該這樣子命名。
不過神奇的是IE9以後能正常地執行,合理的解釋大概為IE9以後瀏覽器能準確解析該方法是物件的方法
而IE9之前會視為關鍵字而執行該方法,但以後還是避免這樣的命名方法吧。
五、總結
要寫前端遲早會遇到這個坑,早點踩也是好事,邊解邊學
瀏覽器不僅版本不同會出問題,連使用哪家的瀏覽器也得注意才行
以後真的要先和客戶確認清楚瀏覽器的部分,不然完成後再修改整體程式碼就不整齊一致了