项目写到最后须要优化的时候,发现有不少首屏用不到的第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