vue3 naiveui 自定义v-loading指令

4 篇文章 0 订阅

1.在sr目录下创建loading文件夹,包含index.ts和index.vue

2.index.ts

import { render, VNode, createVNode } from 'vue'
import Loading from './index.vue'
const vnode: VNode = createVNode(Loading) as VNode

export const vLoading = {
  // 在绑定元素的父组件 及他自己的所有子节点都挂载完成后调用
  mounted: (el: HTMLElement, binding: any) => {
    render(vnode, el)
  },
  // 在绑定元素的父组件 及他自己的所有子节点都更新后调用
  updated: (el: HTMLElement, binding: any) => {
    if (binding.value) {
      vnode?.component?.exposed.show()
    } else {
      vnode?.component?.exposed.hide()
    }
    // 动态添加删除自定义class: loading-parent
    formatterClass(el, binding)
  },
  // 绑定元素的父组件卸载后调用
  unmounted: () => {
    vnode?.component?.exposed.hide()
  },
}
function formatterClass(el: HTMLElement, binding: any) {
  const classStr = el.getAttribute('class')
  const tagetClass: number = classStr?.indexOf('loading-parent') as number
  if (binding.value) {
    if (tagetClass === -1) {
      el.setAttribute('class', classStr + ' loading-parent')
    }
  } else if (tagetClass > -1) {
    const classArray: Array<string> = classStr?.split('') as string[]
    classArray.splice(tagetClass - 1, tagetClass + 15)
    el.setAttribute('class', classArray?.join(''))
  }
}

参数详情参考官网:自定义指令 | Vue.js 

3.index.vue

<!--  -->
<template>
  <div v-if="isShow" class="loading-box">
    <div class="mask" :style="{ background: maskBackground }"></div>
    <div class="loading-content-box">
      <n-spin :theme-overrides="spinThemeOverrides" size="small" />
      <div :style="{ color: textColor }" class="tip">{{ tip }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { NSpin, SpinProps } from 'naive-ui'
import { ref } from 'vue'
type SpinThemeOverrides = NonNullable<SpinProps['themeOverrides']>
const prop = defineProps({
  tip: {
    type: String,
    default() {
      return '加载中...'
    },
  },
  maskBackground: {
    type: String,
    default() {
      return 'rgba(0, 0, 0, 0.8)'
    },
  },
  loadingColor: {
    type: String,
    default() {
      return 'rgba(255, 255, 255, 1)'
    },
  },
  textColor: {
    type: String,
    default() {
      return 'rgba(255, 255, 255, 1)'
    },
  },
})
const spinThemeOverrides: SpinThemeOverrides = {
  color: prop.loadingColor,
}
const isShow = ref(false)
const show = () => {
  isShow.value = true
}
const hide = () => {
  isShow.value = false
}
defineExpose({
  show,
  hide,
  isShow,
})
</script>
<style lang="scss" scoped>
.loading-box {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  z-index: 9999;
  .n-spin {
    color: #ccc;
  }
  .mask {
    width: 100%;
    height: 100%;
  }
  .loading-content-box {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
  .tip {
    font-size: 14px;
    margin-top: 8px;
  }
}
</style>

4.在main.ts中全局引入

import { createApp } from 'vue'
import App from './App.vue'

import { vLoading } from '@/directive/loading/index'
const app = createApp(App)
app.directive('loading', vLoading)

......

5.在任意组件中使用

<div v-loading="loading" class="login-page"></div>

const loading = ref(false)

onMounted(() => {
  loading.value = true
  setTimeout(() => {
    loading.value = false
  })
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值