如何在加载延迟加载的路由组件时显示“加载”动画?
Posted
技术标签:
【中文标题】如何在加载延迟加载的路由组件时显示“加载”动画?【英文标题】:How to display a "loading" animation while a lazy-loaded route component is being loaded? 【发布时间】:2017-12-06 19:05:49 【问题描述】:我已使用 webpack 的代码拆分功能将我的应用程序拆分为多个块,以便在用户访问我的网页时不会下载整个应用程序包。
某些路由所需的块可能相当大,并且可能需要相当长的时间才能下载。这很好,除非用户在单击内部链接时不知道页面实际上正在加载,所以我需要以某种方式显示加载动画或其他东西。
我的路由器是这样配置的:
[
path: '/',
component: () => import(/* webpackChunkName: 'landing' */ './landing.vue'),
,
path: '/foo',
component: () => import(/* webpackChunkName: 'main' */ './foo.vue'),
,
path: '/bar',
component: () => import(/* webpackChunkName: 'main' */ './bar.vue'),
,
]
Vue.js 指南中的Advanced Async Components 展示了如何在解析组件时显示特定的“正在加载”组件——这正是我所需要的,但它也说:
请注意,当在 vue-router 中用作路由组件时,这些属性将被忽略,因为异步组件在路由导航发生之前被预先解析。
如何在 vue-router 中实现这一点?如果这是不可能的,那么延迟加载的组件对我来说几乎毫无用处,因为它会给用户带来糟糕的体验。
【问题讨论】:
【参考方案1】:您可以使用导航守卫来激活/停用显示/隐藏加载组件的加载状态:
如果你想使用类似“nprogress”的东西,你可以这样做:
http://jsfiddle.net/xgrjzsup/2669/
const router = new VueRouter(
routes
)
router.beforeEach((to, from, next) =>
NProgress.start()
next()
)
router.afterEach(() =>
NProgress.done()
)
或者,如果你想就地展示一些东西:
http://jsfiddle.net/h4x8ebye/1/
Vue.component('loading', template: '<div>Loading!</div>')
const router = new VueRouter(
routes
)
const app = new Vue(
data: loading: false ,
router
).$mount('#app')
router.beforeEach((to, from, next) =>
app.loading = true
next()
)
router.afterEach(() =>
setTimeout(() => app.loading = false, 1500) // timeout for demo purposes
)
然后在模板中:
<loading v-if="$root.loading"></loading>
<router-view v-else></router-view>
这也可以很容易地封装在一个非常小的组件中,而不是使用 $root
组件来表示加载状态。
【讨论】:
第二个例子中似乎没有定义 next() 函数;但是,该过程仍在运行,并且文档将其显示为 vuejs 路由器中定义的方法? 嗨,Linus,您能详细说明以下声明吗? “这也可以很容易地封装在一个非常小的组件中,而不是使用 $root 组件来进行加载状态。”不太确定您在这里指的是什么 在深度链接到某个页面(使用 someurl#/foo)时使用beforeEach
无济于事,因为它最初不会被调用。 beforeEnter
可以使用,但最初无法访问“应用程序”。您是否也有在深度链接时显示加载微调器的解决方案?
您可能应该打开一个新主题,我不知道如何在答案的 cmets 中讨论这个问题。
@linusborg 为此创建了自己的问题,请参阅***.com/q/49276470/176140【参考方案2】:
对于它的价值,我将分享我最终为我的情况所做的事情。
我使用的是 Vuex,因此很容易创建任何组件都可以访问的应用程序范围的“加载”状态,但您可以使用任何想要共享此状态的机制。
简化,它的工作原理是这样的:
function componentLoader(store, fn)
return () =>
// (Vuex) Loading begins now
store.commit('LOADING_BAR_TASK_BEGIN');
// (Vuex) Call when loading is done
const done = () => store.commit('LOADING_BAR_TASK_END');
const promise = fn();
promise.then(done, done);
return promise;
;
function createRoutes(store)
const load = fn => componentLoader(store, fn);
return [
path: '/foo',
component: load(() => import('./components/foo.vue')),
,
path: '/bar',
component: load(() => import('./components/bar.vue')),
,
];
所以我要做的就是用我的load()
函数包装每个() => import()
,该函数负责设置加载状态。加载是通过直接观察 Promise 来确定的,而不是依赖于特定于路由器的 before/after 钩子。
【讨论】:
【参考方案3】:您可以在 vuejs 的一个项目中将此代码用于 gobel 路由
const router = new Router(
routes: [
path: '/', name: 'home', component: Home ,
path: '/about', name: 'about', component: About
]
)
router.beforeResolve((to, from, next) =>
// If this isn't an initial page load.
if (to.name)
// Start the route progress bar.
NProgress.start()
next()
)
router.afterEach((to, from) =>
// Complete the animation of the route progress bar.
NProgress.done()
)
【讨论】:
以上是关于如何在加载延迟加载的路由组件时显示“加载”动画?的主要内容,如果未能解决你的问题,请参考以下文章
首次加载时显示collectionView的底部,无需滚动和延迟加载