出于可用性考虑,我建议使用具有自己的 vuex 状态的加载器。
- 这将允许您从任何组件控制它。
- 您可以通过简单的函数调用轻松使用它。
- 自然要避免道具和事件。
首先定义您需要这个特定加载程序的位置:
- 它是否适用于所有 api 调用?
- 一些浏览器密集型任务(例如处理加载的文件)。
- 或者本质上更具体的东西(也许仅在用户尝试登录时才显示加载程序)
如果您的加载程序没有像情况 1 那样与任何组件紧密耦合。那么将加载程序保留在主 vue 文件中会更有意义(如果您使用的是 vue-cli,则使用 App.vue)
像这样:
<template>
<div id="app">
<loader></loader>
<router-view></router-view>
</div>
</template>
<script>
import Loader from './components/shared/loader/Loader'
export default {
name: 'app',
components: {
Loader
}
}
</script>
这样,您就不必在每个其他组件文件中添加 loader.vue。
但首先,我将向您展示我正在使用的加载器组件和存储。
<template>
<div class='loader-container' :class='{"show": show, "hidden": !show}'>
<div class="curved-div">
<div class="colour-magic">
<i class='fa fa-circle-o-notch rotate'></i>
</div>
<div class="loading">
{{ loading }}
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import * as NameSpace from '../../../store/NameSpace'
export default {
data () {
return {
loading: 'Loading...'
}
},
computed: {
...mapGetters({
show: NameSpace.GET_LOADER_STATE
})
}
}
</script>
<style scoped>
.loader-container {
position: fixed;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
}
.curved-div {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%);
border-radius: .3rem;
width: 20rem;
padding:1rem;
background: white;
box-shadow: 0 0 .1rem #fefefe;
}
.curved-div > * {
display: inline-block;
}
.rotate {
border-radius: 50%;
padding: .5rem;
animation-name: rotate;
animation-duration: .7s;
animation-iteration-count: infinite;
animation-delay: 0s;
}
.loading {
text-align: center;
width: 12rem;
font-size: 1.8rem;
}
.show {
visibility: visible;
opacity: 1;
z-index: 1;
transition: opacity 0.5s ease-out, visibility 0.5s ease-out, z-index 0.5s ease-out;
}
.hidden {
opacity: 0;
visibility: hidden;
z-index: 0;
transition: opacity 0.5s ease-out, visibility 0.5s ease-out, z-index 0.5s ease-out;
}
@keyframes rotate {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
.colour-magic {
animation-name: colorMagic;
animation-duration: 20s;
animation-iteration-count: infinite;
animation-delay: 0s;
}
@keyframes colorMagic {
0% { color: rgb(179,10,10); }
10% { color: rgb(227,132,22); }
20% { color: rgb(164,153,7); }
30% { color: rgb(26,171,19); }
40% { color: rgb(19,144,177); }
50% { color: rgb(14,16,221); }
60% { color: rgb(27,9,98); }
70% { color: rgb(58,11,111); }
80% { color: rgb(126,14,129); }
90% { color: rgb(208,19,121); }
100% { color: rgb(198,18,18); }
}
</style>
请注意,我使用 font-awesome 作为加载程序。
这是商店:
import * as NameSpace from '../NameSpace'
// you can also use the namespace: true in your store and eliminate the need of NameSpace.js
const state = {
[NameSpace.LOADER_STATE]: false
}
const getters = {
[NameSpace.GET_LOADER_STATE]: state => {
return state[NameSpace.LOADER_STATE]
}
}
const mutations = {
[NameSpace.MUTATE_LOADER_STATE]: (state, payload) => {
state[NameSpace.LOADER_STATE] = payload
}
}
const actions = {
[NameSpace.LOADER_SHOW_ACTION]: ({ commit }, payload) => {
commit(NameSpace.MUTATE_LOADER_STATE, payload)
}
}
export default {
state,
getters,
mutations,
actions
}
一个用法示例:
// This is not a .vue file it is a .js file, therefore a different way of using the store.
import Vue from 'vue'
import * as NameSpace from 'src/store/NameSpace'
import loaderState from 'src/store/modules/loader'
/**
* Pass the mutation function to reduce the text length
* This function can now be used in the api calls to start/stop the loader
* as the api starts and finishes.
*/
let loaderSwitch = loaderState.mutations[NameSpace.MUTATE_LOADER_STATE].bind(null, loaderState.state)
login (username, password) {
loaderSwitch(true)
return new Promise((resolve, reject) => {
SomeEndpoint.logIn(username, password, {
success (user) {
loaderSwitch(false)
resolve(user.attributes)
},
error (user, error) {
loaderSwitch(false)
reject(errorHelper(error.code))
}
})
})
现在,无论使用登录的组件是什么,加载器组件都不需要保留在那里。