【若依】20、Vue3自定义指令
什么是 Vue 中的指令?
- v-if
- v-for
- v-bind
- ……
这些都是指令。 自定义指令 | Vue.js 自定义指令在 RuoYi 项目中的应用:
1
2
3
4
5
6
7
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:dept:add']"
>新增</el-button>
以上面代码为例,如果当前用户具备system:dept:add
权限,那么这个按钮就展示出来,否则这个按钮就隐藏。
两种作用域
自定义指令有两种作用域,可以是全局自定义指令(当前项目的任何地方都可以使用),也可以是局部自定义指令(就能在定义的 .vue 文件中使用)。
局部自定义指令
自定义一个指令,要求如下:
- 指令的名字为 once-click1。
- 指令在定义的时候,可以加上一个时间参数。
- 这个指令一般加在 button 上,表示 button 在点击完成之后,多长时间内,无法再次点击。
<button v-once-click1="10000">Click Me</button>
表示这个按钮点击之后,会处于禁用状态,10s 之后才可以再次点击,防止用户发送重复请求。
自定义局部指令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<template>
<div>
<div></div>
<div>
<button v-once-click1="10000" @click="handleClick">Click Me</button>
<button v-once-click2="10000" @click="handleClick">Click Me</button>
</div>
</div>
</template>
<script setup name="Test01">
import {ref} from 'vue'
const num = ref(1)
const handleClick = () => {
num.value++
}
const vOnceClick1 = {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
// 延迟执行
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
}
</script>
<style lang='scss' scoped>
</style>
两种传参方式:
v-once-click1:10000
,那么获取参数就是binding.arg
。v-once-click1="10000"
,那么获取参数就是binding.value
。全局自定义指令
```javascript import { createApp } from ‘vue’ import App from ‘./App.vue’ import router from ‘./router’ import store from ‘./store’
// 导入插件 import plugins from ‘./plugins’
createApp(App) .directive(‘once-click2’, { /**
- 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
- 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
- @param el 就是自定义指令所绑定的元素
- @param binding 各种传递的参数都在 binding 上
- @param vNode Vue 编译生成的虚拟节点
- @param prevVnode */ mounted: (el, binding, vnode, prevVnode) => { console.log(el, binding, vnode, prevVnode) el.addEventListener(‘click’, () => { if(!el.disabled) { // 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟 // 禁用 el.disabled = true // 延迟执行 setTimeout(() => { el.disabled = false }, binding.value || 3000) } }) } }) .use(plugins, { fontSize: { small: 12, large: 20 } }) .use(store) .use(router) .mount(‘#app’)
1
2
3
4
5
全局自定义指令和局部自定义指令的唯一区别在全局自定义指令写在 main.js 中(也可以单独写一个 js 文件用来定义各种全局自定义指令,然后在 main.js 中引入这个自定义的指令的文件)。指令的具体的逻辑,定义方式都是一样的。全局自定义指令可以应用在当前项目的任何地方。
### 同时传递两个参数
假设,v-once-click2 这个指令的时间参数,其中的时间单位可以自己传递:
```html
<button v-once-click3:s="10" @click="handleClick">Click Me</button>
全局指令的定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 导入插件
import plugins from './plugins'
createApp(App)
.directive('once-click2', {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
// 延迟执行
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
})
.directive('once-click3', {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
let time = binding.value
if(binding.arg == 's') {
// 使用指令的时候,单位是秒,这里转为 ms,因为 setTimeout 中的时间是 ms
time = time * 1000
}
// 延迟执行
setTimeout(() => {
el.disabled = false
}, time || 3000)
}
})
}
})
.use(plugins, {
fontSize: {
small: 12,
large: 20
}
})
.use(store)
.use(router)
.mount('#app')
处理这个指令的时候,先看一下指令的 binding.arg,如果这个为 s,说明使用指令的时候传递的参数是 s,而 setTimeout 中的参数是 ms,所以乘上 1000。
传递动态参数
自定义指令中,还可以传递动态参数,方式如下: 首先定义一个变量,timeUnit 就是我们要使用的时间单位,但是注意他是一个变量。 然后在页面中,就可以直接使用这个变量了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<template>
<div>
<div></div>
<div>
<button v-once-click1="10000" @click="handleClick">Click Me</button>
<button v-once-click2="10000" @click="handleClick">Click Me</button>
<button v-once-click3:[timeUnit]="10" @click="handleClick">Click Me</button>
</div>
</div>
</template>
<script setup name="Test01">
import {ref} from 'vue'
const num = ref(1)
const handleClick = () => {
num.value++
}
const timeUnit = ref('s')
const vOnceClick1 = {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
// 延迟执行
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
}
</script>
<style lang='scss' scoped>
</style>
自定义权限指令
用户登录成功之后,会从服务端获取到自己的权限以及角色信息,自定义权限指令,则是比较一下用户是否具备某一个空间所需要的角色/权限。 自定义全局的权限控制指令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 导入插件
import plugins from './plugins'
// 这个表示当前用户所具备的权限信息,正常来说,这个数组应该是从服务端获取
const permissions = ['user:list', 'user:edit']
createApp(App)
.directive('once-click2', {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
// 延迟执行
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
})
.directive('once-click3', {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
let time = binding.value
if(binding.arg == 's') {
// 使用指令的时候,单位是秒,这里转为 ms,因为 setTimeout 中的时间是 ms
time = time * 1000
}
// 延迟执行
setTimeout(() => {
el.disabled = false
}, time || 3000)
}
})
}
})
.directive('hasPermission', {
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
// 获取组件所需要的权限 <button v-hasPermission="['user:edit']">编辑用户</button>
// 此时,拿到的 value 就是一个数组 ['user:list', 'user:edit']
const {value} = binding // const value = binding.value
// 接下来就是判断 permissions 数组中是否包含 value 数组中的值
if (value && value instanceof Array && value.length > 0) {
let flag = permissions.some(permission => {
// 如果这里都返回 false,flag 就是 false,如果这里有一个是 true,则 flag 就是 true
return permission.includes(value)
})
if (!flag) {
// 说明当前用户不具备所需要的权限,那么就把 el 从 DOM 树中移除掉
el.parentNode && el.parentNode.removeChild(el)
}
}
}
})
.use(plugins, {
fontSize: {
small: 12,
large: 20
}
})
.use(store)
.use(router)
.mount('#app')
两个地方:
- 遍历数组的时候,使用的 some 函数。
- 从 DOM 树中移除一个元素。
用法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<template>
<div>
<div></div>
<div>
<button v-once-click1="10000" @click="handleClick">Click Me</button>
<button v-once-click2="10000" @click="handleClick">Click Me</button>
<button v-once-click3:[timeUnit]="10" @click="handleClick">Click Me</button>
<button v-hasPermission="['user:edit']">编辑用户</button>
<button v-hasPermission="['user:delete']">删除用户</button>
</div>
</div>
</template>
<script setup name="Test01">
import {ref} from 'vue'
const num = ref(1)
const handleClick = () => {
num.value++
}
const timeUnit = ref('s')
const vOnceClick1 = {
/**
* 首先,自定义指令的钩子函数一共有七个:https://cn.vuejs.org/guide/reusability/custom-directives.html#directive-hooks
* 钩子函数中有参数,这个参数基本和 Vue2 中的自定义指令时候的参数含义一致,一共四个参数
* @param el 就是自定义指令所绑定的元素
* @param binding 各种传递的参数都在 binding 上
* @param vNode Vue 编译生成的虚拟节点
* @param prevVnode
*/
mounted: (el, binding, vnode, prevVnode) => {
console.log(el, binding, vnode, prevVnode)
el.addEventListener('click', () => {
if(!el.disabled) {
// 当发生点击事件的时候,如果 el 没有被禁用,那么就让他默认禁用 3s 钟
// 禁用
el.disabled = true
// 延迟执行
setTimeout(() => {
el.disabled = false
}, binding.value || 3000)
}
})
}
}
</script>
<style lang='scss' scoped>
</style>
本文由作者按照
CC BY 4.0
进行授权