项目写到最后需要优化的时候,发现有很多首屏用不到的第3方js都写在index.html里,严重拖慢的网页的加载速度,这里的第3方组件大多不能通过npm或其他模块安装,所以不能直接用vue里的异步组件,比如高德地图的jssdk和它的ui组件,最简单的方法就是在document里插入script。 所以就有了下面的方案。
先定义一个把js插入到document里的方法
# 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()
}
})
}
在按第3方js依赖的不同 分成各个函数
这里以我项目里的高德地图组件为例,它需要一个主jssdk库和一个提供ui的库,ui库是依赖主库的。
# 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方组件的问题
如果一个页面有多个第3方组件,那只定义一个是否加载完的标志位是不够的,因为组件基本是同时created的,在dom中插入script标签后都会返回resolve,其实这时js是没有加载完的,这时可以加一个是否是第一次请求js的变量。
# 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是否加载完,不然会报错的~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。