vue-router-lazy-loading
HTML
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/welcome">Welcome</router-link>
<router-link to="/hello">Hello</router-link>
<router-view></router-view>
</div>
<template id="loading">
<transition name="loading">
<div class="loading">
<div class="spinner"></div>
</div>
</transition>
</template>
<template id="loader">
<div v-if="isLoading" :is="component"></div>
</template>
CSS
.loading-enter-active, .loading-leave-active {
transition: opacity .5s
}
.loading-enter, .loading-leave-to {
opacity: 0
}
.loading {
display: flex;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
}
.spinner {
border: 16px solid #f3f3f3; /* Light grey */
border-top: 16px solid #3498db; /* Blue */
border-radius: 50%;
width: 60px;
height: 60px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
JavaScript
// pages
const Home = { template: '<div>Home</div>' }
const Welcome = { template: '<div>Welcome to Your Vue.js App</div>' }
const Hello = { template: '<div>Hello World!!</div>' }
// https://webpack.js.org/guides/code-splitting/
// { path: '/', component: () => import(/* webpackChunkname: 'home' */'./Home.vue') }
const router = new VueRouter({
routes: [
{ path: '/', component: () => new Promise(resolve => setTimeout(() => resolve(Home), 1000)) },
{ path: '/welcome', component: () => new Promise(resolve => setTimeout(() => resolve(Welcome), 2000)) },
{ path: '/hello', component: () => new Promise(resolve => setTimeout(() => resolve(Hello), 3000)) }
]
})
const Loading = { template: '#loading' }
const Loader = {
name: 'loader',
template: '#loader',
props: {
component: Object
},
data() {
return {
isLoading: false
}
},
mounted() {
document.body.appendChild(this.$el)
},
destroyed() {
this.$el.remove()
},
methods: {
start() {
this.isLoading = true
},
stop() {
this.isLoading = false
}
}
}
class LoadingHelper {
constructor(component, delay) {
this.loading = false
this.delay = delay
const Ctor = Vue.extend(Loader)
this.loader = new Ctor({
el: document.createElement('div'),
propsData: {
component, delay
}
})
}
get isLoading() {
return this.loading
}
start() {
this.loading = true
setTimeout(() => {
if (this.isLoading) {
this.loader.start()
}
}, this.delay)
}
stop() {
this.loader.stop()
this.loading = false
}
}
const VueLoading = {
install(Vue, {router, component = Loading, delay = 200} = {}) {
const loading = new LoadingHelper(component, delay)
if (router) {
router.beforeEach((to, from, next) => {
loading.start()
next()
})
router.beforeResolve((to, from, next) => {
loading.stop()
next()
})
}
...