web-dev-qa-db-ja.com

遅延読み込みされたルートコンポーネントの読み込み中に「読み込み中」のアニメーションを表示する方法は?

ユーザーがWebページにアクセスしたときにアプリケーションバンドル全体がダウンロードされないように、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ガイドでは、コンポーネントの解決中に特定の「ロード」コンポーネントを表示する方法を示しています-これはまさに私が必要なものですが、それはまた言っています:

Vue-routerでルートコンポーネントとして使用する場合、ルートナビゲーションが発生する前に非同期コンポーネントが事前に解決されるため、これらのプロパティは無視されることに注意してください。

Vue-routerでこれをどのように達成できますか?これが不可能な場合、遅延ロードされたコンポーネントは、ユーザーに悪いエクスペリエンスを提供するため、ほとんど役に立たないでしょう。

19
Decade Moon

ナビゲーションガードを使用して、読み込みコンポーネントを表示/非表示にする読み込み状態を有効/無効にすることができます。

「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((to, from, next) => {
  setTimeout(() => app.loading = false, 1500) // timeout for demo purposes
    next()
})

次に、テンプレートで:

<loading v-if="$root.loading"></loading>
  <router-view v-else></router-view>

また、ロード状態に$ rootコンポーネントを使用する代わりに、非常に小さなコンポーネントに簡単に組み込むことができます。

32
Linus Borg

それが価値があるものについては、私が自分の状況のた​​めにやったことを共有します。

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')),
    },
  ];
}
_

したがって、すべての_() => import()_を、ロード状態の設定を処理するload()関数でラップするだけです。読み込みは、ルーター固有のbefore/afterフックに依存する代わりに、promiseを直接観察することにより決定されます。

2
Decade Moon