【问题标题】: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 中实现这一点?如果这是不可能的,那么延迟加载的组件对我来说几乎毫无用处,因为它会给用户带来糟糕的体验。

【问题讨论】:

    标签: javascript webpack vue.js 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 为此创建了自己的问题,请参阅stackoverflow.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() 函数包装每个() =&gt; 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()
      })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-08
        相关资源
        最近更新 更多