摘要:本文將針對(duì)使用生態(tài)開(kāi)發(fā)完成的網(wǎng)站,以版本為基礎(chǔ)兼容目標(biāo),實(shí)現(xiàn)全功能正常使用的全面兼容解決方案。這樣做的目的,是逐步減少全局性方法,使得語(yǔ)言逐步模塊化。此外,使用這個(gè),一旦頁(yè)面不處于瀏覽器的當(dāng)前標(biāo)簽,就會(huì)自動(dòng)停止刷新。
前言
背景情況
vue - 2.5.11
vue-cli 使用模板 webpack-simple
http請(qǐng)求:axios
Vue 官方對(duì)于 ie 瀏覽器版本兼容情況的描述是 ie9+,即是 ie9 及更高的版本。經(jīng)過(guò)測(cè)試,Vue 的核心框架 vuejs 本身,以及生態(tài)的官方核心插件(VueRouter、Vuex等)均可以在 ie9 上正常使用。
Vue 的作者尤雨溪對(duì)于 Vue 的學(xué)習(xí)建議 中有提及為了將項(xiàng)目更好的生態(tài)化/工程化,要盡可能學(xué)習(xí)及使用新的 ECMAScript 規(guī)范。目前 ES6/ES2015 是可用度和穩(wěn)定度較高的規(guī)范,文檔齊全,國(guó)內(nèi)還有 阮一峰 《ECMAScript 6 入門》 做了大量的文檔翻譯,開(kāi)發(fā)環(huán)境可謂完善。然而版本較舊的瀏覽器并不支持 es6 規(guī)范,尤其是 ie 瀏覽器,即使是最高的 ie11 版本,對(duì)于 es6 規(guī)范也支持得并不全。如此則需要對(duì)所有原生不支持 ES6 特性的瀏覽器做兼容性處理。
本文將針對(duì)使用 Vue 生態(tài)開(kāi)發(fā)完成的網(wǎng)站,以 ie9 版本為基礎(chǔ)兼容目標(biāo),實(shí)現(xiàn)全功能正常使用的全面兼容解決方案。
ES6兼容在 ie9 的環(huán)境上,es6 的部分新對(duì)象、表達(dá)式,并不支持,解決方案是使用 babel-polyfill 組件,它可以將 es6 的代碼翻譯成低版本瀏覽器可以識(shí)別的 es5 代碼
npm i babel-polyfill --save-dev
安裝完成后,在項(xiàng)目的主入口文件 main.js 的首行就可以直接引用
import "babel-polyfill";
在項(xiàng)目使用 vue-cli 生成的代碼中,根目錄有一個(gè) .babelrc 文件,這是項(xiàng)目使用 babel 的配置文件。在默認(rèn)生成的模板內(nèi)容中,增加 "useBuiltIns": "entry" 的設(shè)置內(nèi)容,這是一個(gè)指定哪些內(nèi)容需要被 polyfill(兼容) 的設(shè)置
useBuiltIns 有三個(gè)設(shè)置選項(xiàng)
false - 不做任何操作
entry - 根據(jù)瀏覽器版本的支持,將 polyfill 需求拆分引入,僅引入有瀏覽器不支持的polyfill
usage - 檢測(cè)代碼中 ES6/7/8 等的使用情況,僅僅加載代碼中用到的 polyfill
這里推薦設(shè)置為 entry ,完整的 .babelrc 內(nèi)容如下:
{ "presets": [ [ "env", { "modules": false, "useBuiltIns": "entry" } ], "stage-3" ] }
加入這些代碼后,工程里的大部分內(nèi)容已可兼容到 ie9 版本
Number對(duì)象即使在使用 babel-polyfill 做代碼翻譯后,發(fā)現(xiàn)還是有一些 es6 的新特性并沒(méi)有解決,比如說(shuō) Number 對(duì)象的 parseInt 和 parseFloat 方法
es6 將全局方法 parseInt() 和 parseFloat() ,移植到 Number 對(duì)象上面,行為完全保持不變。這樣做的目的,是逐步減少全局性方法,使得語(yǔ)言逐步模塊化。
解決這個(gè)問(wèn)題不需要引入包來(lái)解決,同樣在項(xiàng)目主入口文件 main.js 加入以下代碼(代碼盡可能靠前,最好是在引用 babel-polyfill 之后 )
if (Number.parseInt === undefined) Number.parseInt = window.parseInt; if (Number.parseFloat === undefined) Number.parseFloat = window.parseFloat;requestAnimationFrame方法
window.requestAnimationFrame 是瀏覽器用于定時(shí)循環(huán)操作的一個(gè)接口,類似于 setTimeout,主要用途是按幀對(duì)網(wǎng)頁(yè)進(jìn)行重繪。
requestAnimationFrame 的優(yōu)勢(shì),在于充分利用顯示器的刷新機(jī)制,比較節(jié)省系統(tǒng)資源。顯示器有固定的刷新頻率(60Hz或75Hz),也就是說(shuō),每秒最多只能重繪60次或75次,requestAnimationFrame 的基本思想就是與這個(gè)刷新頻率保持同步,利用這個(gè)刷新頻率進(jìn)行頁(yè)面重繪。此外,使用這個(gè)API,一旦頁(yè)面不處于瀏覽器的當(dāng)前標(biāo)簽,就會(huì)自動(dòng)停止刷新。這就節(jié)省了CPU、GPU和電力。
不過(guò)有一點(diǎn)需要注意,requestAnimationFrame 是在主線程上完成。這意味著,如果主線程非常繁忙,requestAnimationFrame 的動(dòng)畫(huà)效果會(huì)大打折扣。
window.requestAnimationFrame() 方法告訴瀏覽器您希望執(zhí)行動(dòng)畫(huà)并請(qǐng)求瀏覽器在下一次重繪之前調(diào)用指定的函數(shù)來(lái)更新動(dòng)畫(huà)。該方法使用一個(gè)回調(diào)函數(shù)作為參數(shù),這個(gè)回調(diào)函數(shù)會(huì)在瀏覽器重繪之前調(diào)用。
有部分第三方組件就使用了這個(gè)方法,例如部分文件上傳、圖片處理類的組件;那么在這類型的組件在 ie9 下使用時(shí),會(huì)報(bào)出
SCRIPT5007: Expected object.
window.requestAnimationFrame() 的最低兼容 ie 版本為 10,那么在 ie9 上做兼容就需要制作 requestAnimationFrame polyfill
(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); }; }());
Gist:requestAnimationFrame polyfill
這部分代碼同樣是盡可能在網(wǎng)站入口處就執(zhí)行
http網(wǎng)絡(luò)請(qǐng)求(跨域)在大多數(shù)的 Web 項(xiàng)目中(以 JavaWeb 為例),網(wǎng)站的頁(yè)面和服務(wù)(至少是 controller 層)在同一個(gè)工程進(jìn)行開(kāi)發(fā)和部署,在大前端的新型模式下,我們建議盡可能對(duì)網(wǎng)站的前端和后端進(jìn)行完全分離,前后端分離的好處和意義這里不再贅述。
既然是前后端分離,那么部署也必然是各自獨(dú)立部署,不同的訪問(wèn)路徑,就會(huì)產(chǎn)生跨域訪問(wèn)的問(wèn)題(同一站點(diǎn),不同端口號(hào)也是跨域)
在此設(shè)定背景情況:
服務(wù)端已完整開(kāi)啟 CROS 跨域支持
http 組件使用 axios
axios 設(shè)置 withCredentials 為 true 開(kāi)啟跨域訪問(wèn)時(shí)攜帶 cookie 數(shù)據(jù)
高版本瀏覽器(ie10+ 或 chrome, ff)僅需要完成背景情況中的功能,即可支持跨域數(shù)據(jù)請(qǐng)求功能
axios 進(jìn)行數(shù)據(jù)請(qǐng)求時(shí),默認(rèn)使用 XMLHttpRequest 對(duì)象,在檢測(cè)到當(dāng)前請(qǐng)求是跨域訪問(wèn)時(shí),axios 會(huì)測(cè)試瀏覽器是否支持 XDomainRequest 對(duì)象,若支持則優(yōu)先使用。
ie8 / ie9 的 XMLHttpRequest 對(duì)象,不支持跨域訪問(wèn),該對(duì)象在 ie10 后才原生支持跨域訪問(wèn)。微軟的解決方案是在 ie8 / ie9 中提供了 XDomainRequest(XDR) 對(duì)象來(lái)進(jìn)行解決跨域問(wèn)題,雖然使用該對(duì)象可以跨域訪問(wèn)成功,并返回?cái)?shù)據(jù),但它卻依然是一個(gè)功能不完整的半成品,它的使用有諸多限制:
XDR 僅支持 GET 與 POST 兩種請(qǐng)求方式
XDR 不支持自定義的請(qǐng)求頭,若服務(wù)端使用 header 的自定義參數(shù)進(jìn)行做身份驗(yàn)證,則不可用
請(qǐng)求頭的 Content-Type 只允許設(shè)置為 text/plain
XDR 不允許跨協(xié)議的請(qǐng)求,如果網(wǎng)頁(yè)在 HTTP 協(xié)議下,就只能請(qǐng)求 HTTP 協(xié)議下的接口,不能訪問(wèn) HTTPS 接口
XDR 只接受HTTP/HTTPS 的請(qǐng)求
發(fā)起請(qǐng)求的時(shí)候,不會(huì)攜帶 authentication 或 cookies
微軟雖然提供了解決方案,但卻是不折不扣的雞肋,根本無(wú)法勝任系統(tǒng)中各種場(chǎng)景的數(shù)據(jù)請(qǐng)求需求,至此,axios 對(duì) ie9 的跨域數(shù)據(jù)請(qǐng)求已無(wú)能為力。
完美解決方案:代理(proxy)雖然 axios 對(duì) ie9 跨域已無(wú)能為力,但前端項(xiàng)目打包的解決方案 webpack 提供了一個(gè)優(yōu)雅而徹底解決問(wèn)題的方式:代理
devServer.proxy
webpack 的 devServer.proxy 的功能是由 http-proxy-middleware 項(xiàng)目來(lái)實(shí)現(xiàn)的
實(shí)現(xiàn)原理是將目標(biāo)位置的請(qǐng)求代理為前端服務(wù)本地的請(qǐng)求,既然是代理成為本地的請(qǐng)求,就不存在跨域的問(wèn)題,axios 就會(huì)用回 XMLHttpRequest 對(duì)象進(jìn)行數(shù)據(jù)請(qǐng)求,一切都恢復(fù)正常了,header、cookies、content-type、authentication 等內(nèi)容都被正確傳遞到服務(wù)端。
項(xiàng)目中 webpack.config.js 的配置
devServer: { historyApiFallback: true, noInfo: true, overlay: true, proxy: { "/api": { target: "http://localhost:8081/myserver", pathRewrite: { "^/api": "" } } } }
配置中指定了將 http://localhost:8081/myserver 服務(wù)的位置代理為本地前端服務(wù)的 http://localhost:8080/api。例如需要讀取用戶信息的原請(qǐng)求是 http://localhost:8081/myserver/user/zhangsan,代理后,就變?yōu)?http://localhost:8080/api/user/zhangsan。
即是 /api 的前綴代表了服務(wù)端,所以在使用 axios 時(shí),需要對(duì)每個(gè)服務(wù)端請(qǐng)求都增加上 /api 的前綴;通常在項(xiàng)目開(kāi)發(fā)中,需要對(duì)數(shù)據(jù)請(qǐng)求組件 axios 進(jìn)行二次封裝,以達(dá)到統(tǒng)一設(shè)置默認(rèn)參數(shù),統(tǒng)一數(shù)據(jù)請(qǐng)求入口等目的,那么此時(shí)就只需要在二次封裝的文件里統(tǒng)一調(diào)整請(qǐng)求前綴即可。
不過(guò),webpack 的 devServer.proxy 僅在開(kāi)發(fā)模式下可用,生產(chǎn)模式下無(wú)法使用。開(kāi)發(fā)模式下,調(diào)試服務(wù)可以讀取 webpack.config.js 中的配置內(nèi)容進(jìn)行實(shí)時(shí)代理,而項(xiàng)目在部署到生產(chǎn)環(huán)境前,需要將工程進(jìn)行編譯轉(zhuǎn)換成靜態(tài)的 js 文件,沒(méi)有調(diào)試服務(wù)的支撐自然是無(wú)法進(jìn)行請(qǐng)求代理的。
nginx 配置
雖然 devServer.proxy 的功能僅能工作于開(kāi)發(fā)模式,那么在生產(chǎn)模式下,自然也是有解決方案的;通常 Vue 的項(xiàng)目在編譯成最終的 js 文件后,僅需要靜態(tài)服務(wù)器即可,這其中又以 nginx 為最優(yōu)選擇方案,輕量、高性能、高并發(fā)、反向代理服務(wù)等均為其優(yōu)點(diǎn),這里需要做的數(shù)據(jù)請(qǐng)求代理的功能就使用到了 nginx 的 反向代理 功能
conf/nginx.conf 文件配置增加以下內(nèi)容
location /api/ { proxy_pass http://localhost:8081/myserver/; }
該配置同樣是將 http://localhost:8081/myserver/ 的目標(biāo)服務(wù)端位置代理為本地服務(wù)的 /api 路徑,如此,生產(chǎn)環(huán)境下的數(shù)據(jù)請(qǐng)求問(wèn)題也得以解決
個(gè)人原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)說(shuō)明出處
完整內(nèi)容:https://github.com/TerryZ
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95509.html
摘要:官方的意思是項(xiàng)目可以在以上的版本中運(yùn)行但其實(shí)使用構(gòu)建的項(xiàng)目也還是不能在以上的版本中運(yùn)行下面就來(lái)講如何在以上版本中運(yùn)行安裝在項(xiàng)目入口文件,如本項(xiàng)目中的文件中引用修改配置文件到此編譯項(xiàng)目之后該項(xiàng)目就可以成功在以上的瀏覽器中打開(kāi) showImg(https://segmentfault.com/img/bVbkQJ9?w=662&h=172);vue官方的意思是vue項(xiàng)目可以在ie8以上的i...
摘要:一開(kāi)發(fā)背景為了全面的熟悉技術(shù)棧,結(jié)合的開(kāi)放開(kāi)發(fā)了這個(gè)簡(jiǎn)潔版的。在線預(yù)覽來(lái)自官方以及的整理。當(dāng)頁(yè)面刷新后也無(wú)法顯示,請(qǐng)查看控制臺(tái)的異步請(qǐng)求是否返回。 一、開(kāi)發(fā)背景 為了全面的熟悉Vue+Vue-router+Vuex+axios技術(shù)棧,結(jié)合V2EX的開(kāi)放API開(kāi)發(fā)了這個(gè)簡(jiǎn)潔版的V2EX。 在線預(yù)覽 API來(lái)自官方以及djyde的整理。 在線訪問(wèn)請(qǐng)節(jié)制使用,跨域是通過(guò)Nginx配置反向代...
摘要:原來(lái)對(duì)全局的事件進(jìn)行監(jiān)聽(tīng),一旦發(fā)現(xiàn)就會(huì)嘗試觸發(fā)當(dāng)前文檔激活對(duì)象的事件。事件需要注意的點(diǎn)事件只能綁定在接口對(duì)象上,其他元素綁定無(wú)效,而且不可以取消也不能冒泡需要注意的是上右鍵菜單的剪切并不會(huì)觸發(fā)事件瀏覽器從開(kāi)始支持相關(guān)文檔 文章起因 看Vue源代碼內(nèi)置指令時(shí),發(fā)現(xiàn)了Vue對(duì)于IE9的selectionchange事件做了特殊處理,這引起了我的興趣。原來(lái)Vue對(duì)全局的selectionch...
摘要:也能使用更復(fù)雜的,更頁(yè)面增加更強(qiáng)的效果。這是因?yàn)楫?dāng)頂級(jí)頁(yè)面設(shè)置為或,里面的頁(yè)面設(shè)置不起作用,它的文檔模式顯示的是。參考參考使用來(lái)搞定瀏覽器兼容模式強(qiáng)制標(biāo)準(zhǔn)模式標(biāo)準(zhǔn)模式與兼容模式設(shè)置背景 因?yàn)闅v史原因,之前很多的系統(tǒng)都會(huì)是 頂級(jí)頁(yè)面+Iframe來(lái)加載子級(jí)頁(yè)面的這種模式構(gòu)件系統(tǒng),而且系統(tǒng)都只能運(yùn)行在IE6或者IE 高版本兼容模式下(IE 7模式)。 隨著現(xiàn)在的審美原來(lái)越高,腳本能里越來(lái)越強(qiáng),...
摘要:公司新開(kāi)發(fā)的項(xiàng)目需要兼容到就在頁(yè)面加入不起作用總結(jié)方法兼容可能會(huì)遇到語(yǔ)法或者錯(cuò)誤,安裝在頁(yè)面入口配置中引入解決編譯錯(cuò)誤重要重新安裝一下如果有淘寶鏡像也可使用修改下安裝根目錄下新建以上操作完成后運(yùn)行 公司新開(kāi)發(fā)的項(xiàng)目需要兼容到IE9+ 就在index.html頁(yè)面加入 不起作用 總結(jié)方法: 兼容IE9/IE10可能會(huì)遇到語(yǔ)法或者 Promise錯(cuò)誤,安裝 babel-polyfill...
閱讀 4046·2021-09-30 09:59
閱讀 2542·2021-09-13 10:34
閱讀 651·2019-08-30 12:58
閱讀 1578·2019-08-29 18:42
閱讀 2268·2019-08-26 13:44
閱讀 2995·2019-08-23 18:12
閱讀 3391·2019-08-23 15:10
閱讀 1697·2019-08-23 14:37