1. Loading組件
<template>
<div>
<van-loading :color="loadingList.color" vertical>{{ loadingList.title }}</van-loading>
<div class="mask" v-bind:class="{ 'bottom-mask': loadingList.isBottomMask }"></div>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue'
interface State {
loadingList: {
title: string
color: string
isBottomMask: boolean
}
}
export default defineComponent({
name: 'Loading',
setup() {
const state = reactive<State>({
loadingList: {
title: '加載中...', //提示信息
color: '#c9c9c9', //加載顏色
isBottomMask: false //是否遮住頁面,只顯示返回
}
})
const setLoading = (val: any) => {
state.loadingList = { ...state.loadingList, ...val }
}
return {
...toRefs(state),
setLoading
}
}
})
</script>
<style lang="scss" scoped>
@import '@/style/variables.scss';
.van-loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
// 遮罩層
.mask {
width: 100%;
height: calc(100% - 138px);
background-color: transparent;
position: fixed;
top: 88px;
left: 0;
z-index: 1;
}
.bottom-mask {
height: calc(100% - 88px);
background-color: $background-color-base;
}
</style>
2. directives文件夾下 loading.ts 指令ts
import LoadingComponent from '@/components/Loading.vue'
import { createApp } from 'vue'
import { Loading } from 'vant'
const loading = {
mounted(el: any, binding: any) {
// 創建app對象 根組件為我們寫好的 loading 組件
const loading = createApp(LoadingComponent)
//引入vant組件
loading.component(Loading.name, Loading)
//動態創建一個div節點,將app掛載在div上
const instance = loading.mount(document.createElement('div'))
// 因為在updated也需要用到 instance 所以將 instance 添加在el上 ,在updated中通過el.instance 可訪問到
el.instance = instance
// v-loading傳過來的值儲存在 binding.value 中
if (binding.value?.isLoading) {
el.instance.setLoading(binding.value) //setLoading是LoadingComponent組件的方法,用回調傳參
add(el)
}
},
updated(el: any, binding: any) {
// 如果value的值有改變,那么我們去判斷進行操作
if (binding.value?.isLoading !== binding.oldValue?.isLoading) {
el.instance.setLoading(binding.value)
binding.value?.isLoading ? add(el) : remove(el)
}
}
}
// const className = 'loading-relative' // loading-relative 是我在全局寫的樣式名 {position:relative}
function add(el: any) {
// const style = getComputedStyle(el)
// if (['absolute', 'relative', 'fixed'].indexOf(style.position) === -1) {
// el.classList.add(className) // 通過此API可以添加類名
// }
//向el節點插入動態創建的 div 節點 , 內容就是我們的 loading 組件
el.appendChild(el.instance.$el)
}
function remove(el: any) {
//移除動態創建的 div 節點
el.removeChild(el.instance.$el)
}
export default loading
3. main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'amfe-flexible'
import '@/style/index.scss'
import SvgIcon from './components/SvgIcon.vue'
import Vconsole from 'vconsole'
import loading from './directives/loading'
// 不同瀏覽器一些默認的html標簽的展示行為是不一致的,normalize.css 使樣式在所有瀏覽器上保持一致
import 'normalize.css'
import { components } from './plugins/vant'
process.env.VUE_APP_MODE !== 'production' && new Vconsole()
const app = createApp(App)
components.forEach(component => {
app.component(component.name, component)
})
app.component('svg-icon', SvgIcon)
app.use(store).use(router).directive('loading', loading).mount('#app')
4. 組件頁面調用
<template>
<div
v-loading="{
isLoading: loadingList.isLoading,
title: loadingList.title,
isBottomMask: loadingList.isBottomMask,
}"
></div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
interface LoadingList {
isLoading: boolean;
title: string;
isBottomMask: boolean;
}
const loadingList: LoadingList = {
isLoading: false,
title: "加載中...",
isBottomMask: false,
};
export default defineComponent({
name: "Receipt",
setup() {
const state = reactive({
loadingList,
});
return {
...toRefs(state),
};
},
});
</script>
<style lang="scss" scoped>
</style>