自定义指令,权限按钮实现
自定义指令,权限按钮实现
文章目录
一、自定义指令核心知识点
如果在操作一些原生 DOM 时,一些功能使用频率非常高,可以考虑封装成自定义指令。而它确实也是经常用来封装一些原生操作,因为 Vue 官方给出的一些指令远远不能满足我们的需求。
所以除了 Vue 内置的一系列指令 (比如 v-model
或 v-show
) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
数字化管理平台
Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus
Vue 权限系统案例
个人博客地址
1.1 自定义局部指令
在 <script setup>
中,任何以 v
开头的驼峰式命名的变量都可以被用作一个自定义指令。在下面的例子中,vFocus
即可以在模板中以 v-focus
的形式使用。
1.1.1 获取焦点指令案例
当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦
<script setup>
// 在模板中启用 v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
1.1.2 拖拽指令案例
在 JS 中,拖拽是经常用到的一个指令。很多朋友可能在学习 JS 基础知识的时候,通过原生的方式或复杂或简单的封装过拖拽的案例。今天就在 Vue 自定义指令中,去使用原生实现拖拽效果。
<script setup>
import { ref } from 'vue'
const message = ref("自定义指令")
const vColor = {
mounted(el, binding, vnode, prevVnode) {
console.log(el, "~~~", binding, "~~~", vnode, "~~~", prevVnode);
}
}
// 自定义拖拽指令
const vDrag = {
mounted(el) {
let maxX = document.documentElement.clientWidth - el.clientWidth;
let maxY = document.documentElement.clientHeight - el.clientHeight;
const mouseDownFn = (e) => {
let x = e.clientX;
let y = e.clientY;
const moveFn = (e) => {
let moveX = e.clientX - x;
let moveY = e.clientY - y;
x = e.clientX;
y = e.clientY;
let ml = el.offsetLeft + moveX;
let mt = el.offsetTop + moveY;
if (ml <= 0) {
ml = 0;
} else if (ml >= maxX) {
ml = maxX;
}
if (mt <= 0) {
mt = 0;
} else if (mt >= maxY) {
mt = maxY;
}
el.style.left = ml + "px";
el.style.top = mt + "px";
}
document.addEventListener('mousemove', moveFn)
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', moveFn)
}, false)
}
el.addEventListener('mousedown', mouseDownFn, false)
}
}
</script>
<template>
<div v-drag v-color:myprop.hehe="{ color: 'yellow' }" v-bind:class="{ box: true }">{{ message }}</div>
</template>
<style scoped>
.box {
width: 150px;
height: 150px;
color: #fff;
font-size: 24px;
text-align: center;
line-height: 150px;
background-color: red;
position: fixed;
top: 0;
left: 500px;
cursor: move;
}
</style>
自定义指令 v-color 中配置传参和修饰符,<script setup>
中通过 mounted(el, binding, vnode, prevVnode)
中第二个参数对象 binding 获取:
- arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,arg 为 “foo”。
- modifiers:包含修饰符 (如果有的话) 的对象。例如在 v-my-directive.foo.bar 中,修饰符对象为 {foo: true,bar: true}。
控制台打印参数:
注:自定义指令属于破坏性更新。
1.2 自定义全局指令
将一个自定义指令全局注册到应用层级也是一种常见的做法,这样的话在任何一个组件中都可以调用此全局指令。
如下,在 main.js 中定义一个全局指令:
// 导入 createApp 方法:每个 Vue 应用都是通过 createApp 函数创建一个新的应用实例:
import { createApp } from 'vue'
// 导入根组件
import App from './App.vue'
// 通过 createApp() 函数创建一个新的应用实例
// 我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。
const app = createApp(App)
// 注册全局指令
app.directive('focus',{
mounted: (el) => el.focus()
})
// 挂载应用:应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串
// .mount() 方法应该始终在整个应用配置和资源注册完成后被调用。同时请注意,不同于其他资源注册方法,它的返回值是根组件实例而非应用实例。
app.mount('#app')
在任意组件内调用上面注册的全局指令 v-focus
<template>
<!-- 调用 main.js 中定义的全局指令 v-focus -->
<input v-focus type="text" placeholder="演示自动获取焦点的全局指令">
</template>
页面效果
二、指令钩子
一个指令的定义对象可以提供几种钩子函数 (都是可选的):
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeUnmount
- unmounted
const myDirective = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
指令的钩子会传递以下几种参数:
el
:指令绑定到的元素。这可以用于直接操作 DOM。binding
:一个对象,包含以下属性。value
:传递给指令的值。例如在v-my-directive="1 + 1"
中,值是2
。oldValue
:之前的值,仅在beforeUpdate
和updated
中可用。无论值是否更改,它都可用。arg
:传递给指令的参数 (如果有的话)。例如在v-my-directive:foo
中,参数是"foo"
。modifiers
:一个包含修饰符的对象 (如果有的话)。例如在v-my-directive.foo.bar
中,修饰符对象是{ foo: true, bar: true }
。instance
:使用该指令的组件实例。dir
:指令的定义对象。
vnode
:代表绑定元素的底层 VNode。prevNode
:之前的渲染中代表指令所绑定元素的 VNode。仅在beforeUpdate
和updated
钩子中可用。
三、权限按钮
在前端项目开发过程中,不可避免的就是权限开发。权限开发的复杂度、知识层次,可以看作一个分水岭,评估一个程序员经验的必备之一,经常在面试中必备问道。而按钮权限,也是众多权限中的一种。如何通过按钮,控制用户是否可以操作呢?这里简单的通过指令给大家做一个演示:
<template>
<div class="btns">
<button v-has-show="'shop:create'">创建</button>
<button v-has-show="'shop:edit'">编辑</button>
<button v-has-show="'shop:delete'">删除</button>
</div>
</template>
<script setup>
import { ref, reactive, } from 'vue'
localStorage.setItem('userId','admin')
const permission = [
'admin:shop:create',
'admin:shop:edit',
]
const userId = localStorage.getItem('userId')
const vHasShow = (el,bingding) => {
if(!permission.includes(userId+':'+ bingding.value)){
el.style.display = 'none'
}
}
</script>
<style scoped lang='scss'>
.btns{
button{
margin: 10px;
}
}
</style>