背景
在Vue脚手架项目中,所有以import方式导入的组件的html+css+js等都会编译到app.js文件中----所以这个文件会很大,但是这个文件必然在首屏加载的时候下载。 这就导致了首屏加载慢!
import About from '../components/About.vue';
//一旦这样写,后续项目打包结束将会直接打包到app.js文件中
const routes = [
{
path: '/about',
component: About //引入组件
}
]
异步组件是什么
异步组件是指在加载时什么都没有做,等到实例化组件时才开始加载渲染组件。
定义异步组件时,由原来的选项参数替换为一个函数或返回promise的函数,例如按需加载组件就是它的一个应用,按需加载采用import方式加载组件,实际上就是一个Promise。结合wabpack使用的话,组件会打包成单独的js文件存储在static/js文件夹里面,在调用时使用ajax请求回来插入到html中。
使用方式
普通函数异步组件
Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。可以在工厂函数内执行异步操作,等待异步操作执行完毕后调用resolve()。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
promise异步组件
原来构建组件的选项对象替换成了函数,并且返回一个promise。
Vue.component('bb', function(){
return Promise.resolve({
template: '<div>I am bb</div>'
})
})
如果是wabpack构建的项目,还可以采用import写法。相信这种写法很常见,这就是我们使用的组件懒加载。而import实际上也是返回了一个promise。
Vue.component('aa', () => import('./aa.js'));
高级异步组件
采用这种写法可以定义加载中应当渲染的组件,出错时的组件等。
const cc = () => ({
// 需要加载的组件。应当是一个 Promise
component: new Promise(resolve => {
setTimeout(() => {
resolve({
template: '<div>I am cc</div>'
})
}, 1500);
}),
// 加载中应当渲染的组件
loading: loadingComponent,
// 出错时渲染的组件
error: ErrorComp,
// 渲染加载中组件前的等待时间。默认:200ms。
delay: 200,
// 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
timeout: 3000
})
Vue.component('cc', cc)
如果是wabpack项目里还可以采用以下写法。
const util = {
lazyLoadView: function (asyncView, loadingComponent) {
const AsyncHandler = () => ({
component: asyncView,
loading: loadingComponent,
delay: 1000,
timeout: 10000,
})
return AsyncHandler
}
}
export default util;
import util from './base/util.js'
import loading from './components/common/loading.vue'
export default {
name: 'App',
components: {
'user': util.lazyLoadView(import('./components/home/user.vue'), loading),
},
}
但是上述写法应用于路由组件切换时,可能会导致路由钩子函数无法生效,所以可以考虑使用函数组件的写法来改写组件。
const util = {
lazyLoadView: function (asyncView, loadingComponent) {
const AsyncHandler = () => ({
component: asyncView,
loading: loadingComponent,
delay: 1000,
timeout: 10000,
})
return Promise.resolve({
functional: true,
render(h, { data, children }) {
return h(AsyncHandler, data, children);
}
});
}
}
export default util;
import util from './base/util.js'
import loading from './components/common/loading.vue'
export default {
name: 'App',
components: {
'user': () => util.lazyLoadView(import('./components/home/user.vue'), loading),
},
}
至此,对于高级异步组件还有一点疑问。指定加载中应当渲染的组件loading有啥用,加载一个组件的代码应该是非常快的,只是在这期间显示loading吗,通常组件里面的数据都是网络请求回来的,我们需要的是在数据回来之前都显示loading,而不只是加载组件代码期间。