使用異步元件可以在需要時再載入,Vue.component 第二個參數是傳入元件物件,若要使用異步元件,有三種不同的傳入參數
工廠函數
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
Promise
Vue.component(
'async-webpack-example',
() => import('./my-async-component')
)
物件
物件定義方式的功能比較多,還能定義在異步元件載入前的 loading
元件,設定 delay
幾秒後顯示異步元件
const LoadingComponent = {
template: '<div>Loading...</div>'
};
const ErrorComponent = {
template: '<div>Error!!!</div>'
};
const AsyncComponent = () => ({
component: import('./MyComponent.vue'),
loading: LoadingComponent,
error: ErrorComponent,
delay: 200,
timeout: 3000
})
resolveAsyncComponent
處理上面三種異步元件的創建方式
// src/core/vdom/helpers/resolve-async-component.js
export function resolveAsyncComponent (
factory: Function,
baseCtor: Class<Component>,
context: Component
): Class<Component> | void {
if (isTrue(factory.error) && isDef(factory.errorComp)) {
return factory.errorComp
}
if (isDef(factory.resolved)) {
return factory.resolved
}
if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
return factory.loadingComp
}
if (isDef(factory.contexts)) {
factory.contexts.push(context)
} else {
const contexts = factory.contexts = [context]
let sync = true
const forceRender = () => {
for (let i = 0, l = contexts.length; i < l; i++) {
contexts[i].$forceUpdate()
}
}
const resolve = once((res: Object | Class<Component>) => {
factory.resolved = ensureCtor(res, baseCtor)
if (!sync) {
forceRender()
}
})
const reject = once(reason => {
process.env.NODE_ENV !== 'production' && warn(
`Failed to resolve async component: ${String(factory)}` +
(reason ? `\nReason: ${reason}` : '')
)
if (isDef(factory.errorComp)) {
factory.error = true
forceRender()
}
})
const res = factory(resolve, reject)
if (isObject(res)) {
if (typeof res.then === 'function') {
// () => Promise
if (isUndef(factory.resolved)) {
res.then(resolve, reject)
}
} else if (isDef(res.component) && typeof res.component.then === 'function') {
res.component.then(resolve, reject)
if (isDef(res.error)) {
factory.errorComp = ensureCtor(res.error, baseCtor)
}
if (isDef(res.loading)) {
factory.loadingComp = ensureCtor(res.loading, baseCtor)
if (res.delay === 0) {
factory.loading = true
} else {
setTimeout(() => {
if (isUndef(factory.resolved) && isUndef(factory.error)) {
factory.loading = true
forceRender()
}
}, res.delay || 200)
}
}
if (isDef(res.timeout)) {
setTimeout(() => {
if (isUndef(factory.resolved)) {
reject(
process.env.NODE_ENV !== 'production'
? `timeout (${res.timeout}ms)`
: null
)
}
}, res.timeout)
}
}
}
sync = false
return factory.loading
? factory.loadingComp
: factory.resolved
}
}
Promise
Vue.component(
'async-webpack-example',
() => import('./my-async-component')
)
執行完 const res = factory(resolve, reject)
,返回值就是 import('./my-async-component')
的返回值(Promis 物件),接著滿足 if 條件進入執行,當異步元件 loading 成功執行 resolve
,loading 失敗執行 reject
// src/core/vdom/helpers/resolve-async-component.js
if (isUndef(factory.resolved)) {
res.then(resolve, reject)
}