Как отобразить анимацию "загрузки" при загрузке компонента с ленивым загрузчиком?
Я разделил свое приложение на несколько фрагментов с функцией разделения кода веб-пакета, чтобы весь пакет приложений не загружался, когда пользователь посещает мою веб-страницу.
Куски, которые требуются для некоторых маршрутов, могут быть достаточно большими и могут занимать значительное количество времени для загрузки. Это прекрасно, за исключением того, что пользователь не знает, что страница загружается, когда они нажимают на внутреннюю ссылку, поэтому мне нужно каким-то образом отобразить анимацию загрузки или что-то в этом роде.
Мой маршрутизатор настроен следующим образом:
[
{
path: '/',
component: () => import(/* webpackChunkName: 'landing' */ './landing.vue'),
},
{
path: '/foo',
component: () => import(/* webpackChunkName: 'main' */ './foo.vue'),
},
{
path: '/bar',
component: () => import(/* webpackChunkName: 'main' */ './bar.vue'),
},
]
Advanced Async Components в руководстве Vue.js показывает, как отображать конкретный компонент загрузки при разрешении компонента - это это то, что мне нужно, однако оно также говорит:
Обратите внимание, что при использовании в качестве компонента маршрута в 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((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-компонента для состояния загрузки.
Ответ 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')),
},
];
}
Поэтому все, что мне нужно сделать, это обернуть every () => import()
моей функцией load()
которая заботится о настройке состояния загрузки. Загрузка определяется путем непосредственного наблюдения за обещанием, а не для того, чтобы зависеть от конкретного маршрутизатора до/после хуков.