降版到IE8遇到的問題

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之前會視為關鍵字而執行該方法,但以後還是避免這樣的命名方法吧。

 

五、總結

要寫前端遲早會遇到這個坑,早點踩也是好事,邊解邊學

瀏覽器不僅版本不同會出問題,連使用哪家的瀏覽器也得注意才行

以後真的要先和客戶確認清楚瀏覽器的部分,不然完成後再修改整體程式碼就不整齊一致了