是時候亮出這張圖了:
可是ie不是你不想相容就不相容啊。說多了都是淚。
使用iview已經有一年多的時間。總的來說,iview還是給我的工作帶來了很大的方便。
主要的吐槽點就是文件寫的不夠清楚。
比如元件的按需引入,寥寥數語,看完按照文件引入了,結果控制檯一直報錯。
然後到隔壁element一看,原來引入方式並不是只有一種,有的需要通過vue.prototype.xxx這種方式。
還有對於相容性的描述,
你這麼一說我還以為ie9直接引入polyfill就可以用了呢,誰知道根本不行。在github上提issue又說不支援低版本ie了。
根據我的經驗,不需要很大改動,相容性大概ie10+,這也是element官方文件上的相容性。
不知道iview這麼做是為了吸引更多人入坑還是怎麼回事,畢竟大多數開發者開發的時候都是先看官方文件而不是先去github找issue。
吐槽歸吐槽,iview總體上還是不錯的。下面說一下我在使用iview的過程中所遇到的ie9+的相容性問題及解決方案。
安裝babel-polyfill
IE瀏覽器沒有內建Promise物件。不僅如此,幾乎所有的ES6新增的方法在IE都不能用,此時你需要babel Polyfill
-
首先
npm install babel-polyfill --save 複製程式碼
-
修改webpack.base.conf.js
修改前
entry: { main: './src/main', }, 複製程式碼
修改後
entry: { main: ["babel-polyfill","./src/main"], }, 複製程式碼
看到網上有的教程安裝完babel-polyfill又要安裝es6-prommise,只能說一句:畫蛇添足。
相容dataset
[Vue warn]: Error in directive transfer-dom inserted hook: "TypeError: 無法獲取未定義或 null 引用的屬性“transfer”"
這是ie10及以下不支援dataset導致的,而iview的transfer-dom.js使用了這個屬性
解決辦法:在main.js加入如下程式碼
if (window.HTMLElement) {
if (Object.getOwnPropertyNames(HTMLElement.prototype).indexOf('dataset') === -1) {
Object.defineProperty(HTMLElement.prototype, 'dataset', {
get: function () {
var attributes = this.attributes; // 獲取節點的所有屬性
var name = [];
var value = []; // 定義兩個陣列儲存屬性名和屬性值
var obj = {}; // 定義一個空物件
for (var i = 0; i < attributes.length; i++) { // 遍歷節點的所有屬性
if (attributes[i].nodeName.slice(0, 5) === 'data-') { // 如果屬性名的前面5個字元符合"data-"
// 取出屬性名的"data-"的後面的字串放入name陣列中
name.push(attributes[i].nodeName.slice(5));
// 取出對應的屬性值放入value陣列中
value.push(attributes[i].nodeValue);
}
}
for (var j = 0; j < name.length; j++) { // 遍歷name和value陣列
obj[name[j]] = value[j]; // 將屬性名和屬性值儲存到obj中
}
return obj; // 返回物件
},
});
}
}
複製程式碼
降級依賴版本
如果遇到以下錯誤:
錯誤1:“webpackJsonp”未定義
解決方案:
更改webpack-dev-server版本為2.71或更低
npm install --save-dev webpack-dev-server@2.7.1
複製程式碼
相容requestAnimationFrame(ie9)
ie9是不支援requestAnimationFrame的,如果你使用了出現錯誤,那也沒關係,往下看就行了。
解決方案:新增以下程式碼到main.js
// window.requestAnimationFrame多瀏覽器相容問題補丁
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function () {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
}());
複製程式碼
相容classList(ie9)
錯誤資訊:
無法獲取未定義或 null 引用的屬性“add”
無法獲取未定義或 null 引用的屬性“remove”
如果你檢視sourceMap發現了classList().add或classList.remove()等等,那肯定是classList的問題了。
解決方案:新增以下程式碼到main.js
if (!('classList' in document.documentElement)) {
Object.defineProperty(HTMLElement.prototype, 'classList', {
get: function () {
var self = this;
function update(fn) {
return function (value) {
var classes = self.className.split(/\s+/g);
var index = classes.indexOf(value);
fn(classes, index, value);
self.className = classes.join(' ');
};
}
return {
add: update(function (classes, index, value) {
if (!~index) classes.push(value);
}),
remove: update(function (classes, index) {
if (~index) classes.splice(index, 1);
}),
toggle: update(function (classes, index, value) {
if (~index) { classes.splice(index, 1); } else { classes.push(value); }
}),
contains: function (value) {
return !!~self.className.split(/\s+/g).indexOf(value);
},
item: function (i) {
return self.className.split(/\s+/g)[i] || null;
},
};
},
});
}
複製程式碼
專案內路由跳轉避免使用location.href
為了更好的效能,我們通常會採用路由懶載入。在單頁面應用中,每開啟一個頁面基本上都只載入對應的資原始檔。
如果跳轉到之前的頁面,通常頁面會採用快取的資原始檔,不會再次載入,這樣有效提高了頁面載入效率。
而如果採用location.href這種方式,頁面會全部重新整理,重新下載所有頁面資源,不能很好的利用快取。
這些可以從chrome控制檯的network去檢視。
更重要的是,如果直接採用location.href,ie瀏覽器可能會出現url變化頁面不重新整理的情況!
比如路由如下:
127.0.0.1:8080/#/home
127.0.0.1:8080/#/about
當前頁面是127.0.0.1:8080/#/home,
點選按鈕跳轉
jump(){
location.href = '/#/about'
}
複製程式碼
你會發現,瀏覽器位址列url變了,然後頁面還是home頁面! 所以你應該這樣用
jump(){
let url = '/#/about';
let path = url.split('#')[1];
this.$router.push(path);
}
複製程式碼
這下跳轉就沒問題了。
當然,如果你有一些地方必須要使用location.href,比如你接入了第三方的一些服務,你無法控制,也有解決方法:在vue根例項的created或者mounted生命週期新增如下程式碼:
window.addEventListener('hashchange', () => {
let currentPath = window.location.hash.slice(1);
if (this.$route.fullPath !== currentPath) {
this.$router.push(currentPath);
}
}, false);
複製程式碼
通過監聽hashchange,一旦發現當前頁面url與瀏覽器位址列url不同,就呼叫vue的路由方法跳轉到位址列url去。
如果目的頁面被keep-alive也會觸發這個方法,但是沒有影響。
使用scrollTop
如果頁面太長,我們會加個滾動到頂部的按鈕
toTop(el){
el.scrollTo(0, 0);
}
複製程式碼
誰知道ie下竟然無動於衷!嘗試了一番,才發現是ie瀏覽器不支援scrollTo所致。
改成這樣:
toTop(el){
if (el && el.scrollTo) {
el.scrollTo(0, 0);
} else {
el.scrollTop = 0;
}
}
複製程式碼
ie也可以滾動到頂部了。
ie9不支援cors跨域
這點是最坑的,頁面在ie10+開啟雖然有些地方也會報錯,但是ie9完全不會展示頁面,也就是說一個頁面都展示不出來!
控制檯報錯:訪問拒絕!
除此之外再無其他資訊。
反覆檢視axios和vue的文件,都說支援ie9.
這問題折磨了我好久,沒有具體錯誤資訊,根本無從下手。
一個一個排查,不會是axios的問題吧。
一查發現果然是:ie8/9不支援cors跨域方案,取而代之的是ie的XDomainRequest方法
不想再去研究XDomainRequest方法了。直接用webpack-dev-server提供的伺服器代理方法(前提是後臺已經配置好跨域),大概這樣:
devServer: {
port: 8080,
proxy: {
'/api': {
target: 'http://xx.xx.cn/',
pathRewrite: {'^/api' : ''},
changeOrigin: true
}
}
}
複製程式碼
想要了解更多的可以看看這個IE8、9 下的資源跨域請求
日期格式化不要使用new Date(yy-mm-dd)
在ie瀏覽器下,如果直接使用例如new Date('2018-09-12'),ie會顯示Invalid Date,為了保證在所有瀏覽器表現一致,應該採用new Date('2018/09/12')這種方式。
判斷瀏覽器版本
function IEVersion () {
var userAgent = navigator.userAgent; // 取得瀏覽器的userAgent字串
var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; // 判斷是否IE<11瀏覽器
var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; // 判斷是否IE的Edge瀏覽器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
if (isIE) {
var reIE = new RegExp('MSIE (\\d+\\.\\d+);');
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp['$1']);
if (fIEVersion === 7) {
return 7;
} else if (fIEVersion === 8) {
return 8;
} else if (fIEVersion === 9) {
return 9;
} else if (fIEVersion === 10) {
return 10;
} else {
return 6;// IE版本<=7
}
} else if (isEdge) {
return 'edge';// edge
} else if (isIE11) {
return 11; // IE11
} else {
return -1;// 不是ie瀏覽器
}
};
複製程式碼
一些新特性不要用
用了translateX()發現ie9無動於衷,還是乖乖用相對定位吧;
線性漸變linear-gradient()可以用,但是ie不會識別的,所以先設定一個純色背景或圖片背景再設定線性漸變吧,不然ie背景設定不上。
flex佈局是挺爽,但是別用。想要同樣的效果,table佈局也不錯。