公共指令
说明: 封装公共指令,v-hasPermission、v-copy、v-debounce、v-throttle
效果如图:
1.权限指令v-hasPermission
import { useUserStore } from '@/stores/user'
import type { Directive, DirectiveBinding } from 'vue'
/**
* 权限指令
* 用于根据用户角色控制元素是否显示
*/
const hasPermission: Directive = {
/**
* 指令挂载时执行
* @param el - 绑定指令的DOM元素
* @param binding - 指令绑定对象,包含权限值
*/
mounted: function (el: HTMLElement, binding: DirectiveBinding) {
// 获取用户状态存储
const store = useUserStore()
// 获取绑定的权限值
const values = binding.value
// 添加指令修饰符,用于反转权限判断逻辑
const { not } = binding.modifiers
const checkPermission = () => {
// 处理权限值为字符串的情况
if (typeof values === 'string') {
// 如果用户角色不包含该权限值,则移除元素
const flag = not ? store.roles.includes(values) : !store.roles.includes(values)
if (flag) {
el.style.display = 'none'
} else {
el.style.display = ''
}
}
// 处理权限值为数组的情况
if (Array.isArray(values)) {
// 如果用户角色不包含数组中的任何一个权限值,则移除元素
const flag = not
? values.some((item) => store.roles.includes(item))
: !values.some((item) => store.roles.includes(item))
if (flag) {
el.style.display = 'none'
} else {
el.style.display = ''
}
}
}
checkPermission()
// 根据store中数据,动态更新权限
store.$subscribe(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(mutation, _state) => {
const { events } = mutation
if ((events as any).key === 'roles') {
checkPermission()
}
},
{ deep: true }
)
}
}
export default hasPermission
2.防抖指令v-debounce
/**
* 防抖指令v-debounce
* 用于在元素上添加防抖点击功能,避免用户快速连续点击导致的重复* 操作,最后只执行一次点击
*/
export default {
/**
* 指令挂载时执行的函数
* @param {HTMLElement} el - 绑定指令的DOM元素
* @param {Object} binding - 指令绑定的值对象
*/
mounted: function (el, binding) {
// 检查绑定值是否为函数,如果不是则抛出错误
if (typeof binding.value !== 'function') {
throw 'callback must be a function'
}
let timer: any | null = null
el.__handleClick = function () {
if (timer) {
clearInterval(timer)
}
timer = setTimeout(() => {
binding.value()
}, 500)
}
el.addEventListener('click', el.__handleClick)
},
beforeUnmount: function (el) {
el.removeEventListener('click', el.__handleClick)
}
}
3.节流指令v-throttle.ts
/**
* 节流指令v-throttle
*/
export default {
/**
* 指令挂载时执行的函数
* @param {HTMLElement} el - 绑定指令的DOM元素
* @param {Object} binding - 指令绑定的值对象
*/
mounted: function (el, binding) {
// 检查绑定值是否为函数,如果不是则抛出错误
if (typeof binding.value !== 'function') {
throw 'callback must be a function'
}
// 创建一个定时器变量,初始值为null
let timer: any | null = null
// 为元素添加一个自定义的点击处理函数
el.__handleClick = function () {
// 如果已存在定时器,则清除定时器
if (timer) {
clearInterval(timer)
}
// 如果元素未被禁用,则禁用它并执行回调函数
if (!el.disabled) {
el.disabled = true
binding.value()
// 设置一个定时器,1秒后重新启用元素
timer = setTimeout(() => {
el.disabled = false
}, 1000)
}
}
// 为元素添加点击事件监听器
el.addEventListener('click', el.__handleClick)
},
// 组件卸载前执行的函数,用于清理事件监听器
beforeUnmount: function (el) {
// 移除之前添加的点击事件监听器,防止内存泄漏
el.removeEventListener('click', el.__handleClick)
}
}
4.复制指令 v-copy
/**
* 复制指令:v-copy
*/
import { useClipboard } from '@vueuse/core'
import { ElMessage } from 'element-plus'
export default {
mounted: function (el, binding) {
// 将数据添加到元素标签上
el.copyData = binding.value
const { copy } = useClipboard({ source: binding.value })
const handleClick = () => {
// 复制内容
copy(el.copyData)
ElMessage.success('复制成功')
}
el.addEventListener('click', handleClick)
el.__handleClick = handleClick
},
updated: function (el, binding) {
el.copyData = binding.value
},
beforeUnmount: function (el) {
// 移除监听事件
el.removeEventListener('click', el.__handleClick)
}
}
5.demo实现
<div class="w-full h-full p-10">
<div class="flex w-full justify-center items-center border py-4">
<span>复制指令:</span>
<span v-copy="copyData">点我进行复制</span>
</div>
<div class="flex w-full justify-center items-center border py-4 mt-4">
<span>防抖指令:</span>
<el-button v-debounce="debounceClick">防抖点击</el-button>
</div>
<div class="flex w-full justify-center items-center border py-4 mt-4">
<span>节流指令:</span>
<el-button v-debounce="throttleClick">节流点击</el-button>
</div>
<div class="flex w-full justify-center items-center border py-4 mt-4">
<span>权限指令:</span>
<el-button v-hasPermission="['user']">权限控制按钮</el-button>
</div>
</div>
</template>
<script setup lang="ts">
definePage({
meta: {
title: '基础指令',
icon: 'material-symbols:keyboard-command-key'
}
})
const copyData = ref<string>('点我进行复制')
const debounceClick = () => {
console.log('防抖点击')
}
const throttleClick = () => {
console.log('节流点击')
}
</script>
<style scoped></style>