需求:请求数据时,显示一个长宽100%的半透明遮罩层,可以自定义遮罩层的颜色和提示文本
涉及知识:teleport、axios的拦截器
代码示例
在store里定义控制组件显示与否的变量isLoading和触发改变的mutations方法setLoading
export interface GlobalDataProps {
loading: boolean;
}
const store = createStore<GlobalDataProps>({
state: {
loading: false
},
mutations: {
setLoading(state, status) {
state.loading = status
}
})
在main.js里设置axios的拦截器,通过commit调用store里的mutations方法,改变isLoading的值,从而控制加载组件的显示
import axios from 'axios'
axios.interceptors.request.use(config => {
store.commit('setLoading', true)
return config
})
axios.interceptors.response.use(config => {
store.commit('setLoading', false)
return config
})
loader组件:
组件因为是要实现遮罩在最外层的,如果不使用teleport,组件就会在app组件下,不符合设计之初。
在setup的时候组件还完全没有挂载到dom节点上,此时进行dom节点操作,新增一个在teleport里设定的id为back的节点,
那么loader组件挂载的时候就会挂载到这个新增的节点上,
注意,页面卸载的时候要记得把新增的节点删除,否则多个页面之间频繁跳转后,就会多出很多无用的节点
<template>
<teleport to="#back">
<div
class="d-flex justify-content-center align-items-center h-100 w-100 loading-container"
:style="{backgroundColor: background || ''}"
>
<div class="loading-content">
<div class="spinner-border text-primary" role="status">
<span class="sr-only">{{ text || 'loading'}}</span>
</div>
<p v-if="text" class="text-primary small">{{text}}</p>
</div>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent, onUnmounted } from 'vue'
export default defineComponent({
props: {
text: {
type: String
},
background: {
type: String
}
},
setup() {
const node = document.createElement('div')
node.id = 'back'
document.body.appendChild(node)
onUnmounted(() => {
document.body.removeChild(node)
})
}
})
</script>
<style>
.loading-container {
background: rgba(255, 255, 255, .5);
z-index: 100;
position: fixed;
top: 0;
left: 0;
}
.loading-container {
text-align: center;
}
</style>
在App.vue中调用
<loader v-if="isLoading" text="玩命加载中" background="rgba(0,0,0,0.8)"></loader>