項目寫到最後須要優化的時候,發現有不少首屏用不到的第3方js都寫在index.html裏,嚴重拖慢的網頁的加載速度,這裏的第3方組件大多不能經過npm或其餘模塊安裝,因此不能直接用vue裏的異步組件,好比高德地圖的jssdk和它的ui組件,最簡單的方法就是在document裏插入script。 因此就有了下面的方案。javascript
# asyncLoadJs.js export default function asyncLoadJs (url) { return Q.Promise((resolve, reject) => { let hasLoaded = $('script[src="'+url+'"]').length > 0 if (hasLoaded) { resolve() return } let script = document.createElement('script') script.type = 'text/javascript' script.src = url document.body.appendChild(script) script.onload = () => { resolve() } script.onerror = () => { reject() } }) }
這裏以我項目裏的高德地圖組件爲例,它須要一個主jssdk庫和一個提供ui的庫,ui庫是依賴主庫的。html
# asyncLoadJs.js export function loadAMapJS () { return Q.Promise((resolve, reject) => { asyncLoadJs('https://webapi.amap.com/maps?v=1.3&key=[你本身的key]&plugin=AMap.ToolBar,AMap.Geolocation,AMap.Autocomplete') .then(() => { return asyncLoadJs('https://webapi.amap.com/ui/1.0/main.js') }) .then(() => { resolve() }) .catch(err => { reject(err) }) }) }
# position-picker.vue <script> import {loadAMapJS} from '../../libs/asyncLoadJs' let loadedAMapJS = false // 是否加載完js export default { created () { // 判斷是否加載過 if (!loadedAMapJS) { loadAMapJS().then(() => { loadedAMapJS = true }) } }, mounted () { // 循環判斷有沒有加載完 寫在mounted生命週期裏是應爲高德的api依賴dom let interval = setInterval(() => { if (loadedAMapJS) { clearInterval(interval) this.init() } }, 300) }, init () { let AMap = window.AMap let AMapUI = window.AMapUI AMapUI.loadUI(['misc/PositionPicker'], function (PositionPicker) { self.map = new AMap.Map(self.$refs['map'], { zoom: 16, scrollWheel: false }) ...其餘代碼 }) } } </script>
若是一個頁面有多個第3方組件,那隻定義一個是否加載完的標誌位是不夠的,由於組件基本是同時created的,在dom中插入script標籤後都會返回resolve,其實這時js是沒有加載完的,這時能夠加一個是不是第一次請求js的變量。vue
# position-picker.vue <script> import {loadAMapJS} from '../../libs/asyncLoadJs' let loadedAMapJS = false // 是否加載完js let firstLoadingAMapJS = true // 否是第一次請求 export default { created () { // 判斷是否加載過 if (!loadedAMapJS && firstLoadingAMapJS) { firstLoadingAMapJS = false // 立刻置爲false 只讓第一個created組件去請求js loadAMapJS().then(() => { loadedAMapJS = true }).catch(() => { firstLoadingAMapJS = true // 出錯置爲true 下次進來仍是能從新請求js }) } } ... } </script>
在computed或watch中,若是須要用到第3方js方法的地方必須先判斷第3方js是否加載完,否則會報錯的~java