vue的自定义指令 - Directive
vue除了提供了默认内置的指令外 (例如:v-model 和 v-show),还允许开发人员根据实际情况自定义指令,它的作用价值在于当开发人员在某些场景下需要对普通DOM元素进行操作的时候。Vue自定义指令和组件一样存在着 全局注册 和 局部注册 两种方式。注册全局指令的方式,是通过 Vue.directive( id, [definition] ) 方法:2. 局部注册通过在vue实例中添加 d
一、简介
vue除了提供了默认内置的指令外 (例如:v-model 和 v-show),还允许开发人员根据实际情况自定义指令,它的作用价值在于当开发人员在某些场景下需要对普通DOM元素进行操作的时候。
二、使用
Vue自定义指令和组件一样存在着 全局注册 和 局部注册 两种方式。
1. 全局注册
注册全局指令的方式,是通过 Vue.directive( id, [definition] ) 方法:
- 第一个参数 id :自定义指令名称;
注意:指令名称不需要加 v- 前缀,默认是自动加上前缀的,使用指令的时候一定要加上前缀。 - 第二个参数:可以是对象数据,也可以是一个指令函数。
<template>
<div id="app">
<-- v-focus为自定义指令 -->
<input type="text" placeholder="我是全局自定义指令" v-focus>
</div>
</template>
<script>
// 注册全局指令
Vue.directive("focus", {
inserted(el){
el.focus();
}
})
new Vue({
el: "#app"
})
</script>
2. 局部注册
通过在vue实例中添加 directives 对象数据,可以注册局部自定义指令。
我们还是以全局注册的案例为例,通过注册一个 v-focus 指令,实现了在页面加载完成之后自动让输入框获取到焦点的小功能。其中 inserted 是自定义指令的钩子函数,后面的内容会详细讲解。
<template>
<div>
<input type="text" placeholder="我是局部自定义指令" v-focus>
</div>
</template>
<script>
export default {
name: 'index',
directives: {
focus: {
//自定义指令的钩子函数:
inserted (el, binding, vnode) {
el.focus()
}
}
}
}
</script>
页面效果:
三、钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
- bind:只调用一次,指令 第一次绑定到元素时 调用。在这里可以进行一次性的初始化设置;
- inserted:被绑定元素 插入父节点时 调用 (仅保证父节点存在,但不一定已被插入文档中);
- update:所在组件的 VNode 更新时 调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有;
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后 调用;
- unbind:只调用一次,指令与元素 解绑时 调用。
四、钩子函数参数
指令钩子函数会被传入以下参数:
-
el:指令所绑定的元素,可以用来直接操作 DOM;
-
binding:一个对象,包含以下 property:
-
name:指令名,不包括 v- 前缀;
-
value:指令的绑定值,例如:v-focus=“1 + 1” 中,value为 2;
-
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用(无论值是否改变都可用);
-
expression:字符串形式的指令表达式,例如 v-focus=“1 + 1” 中,表达式为 “1 + 1”。
-
arg:传给指令的参数,可选。例如 v-focus:message 中,参数为 “message”;
-
modifiers:一个包含修饰符的对象。例如:v-focus.a.b 中,修饰符对象为 {a: true,b: true}。
-
vnode:Vue 编译生成的 虚拟节点;
- oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
<input type="text" placeholder="我是局部自定义指令" v-focus:message.a.b="1+1">
directives: {
focus: {
inserted (el, binding, vnode) {
el.focus()
console.log(el)
console.log(binding.name)
console.log(binding.value)
console.log(binding.arg)
console.log(binding.expression)
console.log(binding.modifiers)
console.log(vnode)
}
}
}
动态指令参数:
指令的参数可以是动态的。例如,在 v-mydirective:[argument]=“value” 中,argument 参数可以根据组件实例数据进行更新。
例如:我们想要创建一个通过指令值来更新竖直位置像素值的自定义指令:
<template>
<div class="box" v-pin="200"></div>
</template>
<script>
export default {
name: 'index',
directives: {
pin: {
bind (el, binding) {
el.style.position = 'fixed'
el.style.top = binding.value + 'px'
}
}
}
}
</script>
页面效果:
这样就可以把该元素固定在距离页面顶部 200 像素的位置,但是如果想把元素固定在左侧而不是顶部又该怎么办呢?这时使用动态参数就可以非常方便地根据每个组件实例来进行更新。
<template>
<div class="box" v-pin:[direction]="200"></div>
</template>
<script>
export default {
name: 'Directive',
data () {
return {
direction: 'left'
}
},
directives: {
pin: {
bind (el, binding) {
el.style.position = 'fixed'
let direction = binding.arg ? binding.arg : 'left'
el.style[direction] = binding.value + 'px'
}
}
}
}
</script>
这样这个自定义指令现在的灵活性就足以支持一些不同的用例了。
五、函数简写
在很多时候,我们可能只想在 bind 和 update 时触发相同行为,而不关心其它的钩子。
可以将自定义指令这样简写:
directives: {
pin (el, binding) {
el.style.position = 'fixed'
el.style[binding.arg] = binding.value + 'px'
}
}
六、对象字面量
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。
指令函数能够接受所有合法的 JavaScript 表达式。
<template>
<div class="box" v-pin="{color:'red',text: 'box'}"></div>
</template>
<script>
export default {
name: 'Directive',
data () {
return {
direction: 'left'
}
},
directives: {
pin (binding) {
console.log(binding.value.color) // red
console.log(binding.value.text) // box
}
}
}
</script>
七、批量注册指令
- 新建 directives 文件夹,将所有自定义指令的 js 文件全部放到这里:
focus.js:
export default {
inserted (el) {
el.focus()
}
}
- 在 directives 文件中新建 index.js ,引入所有的自定义指令文件,并进行 全局的批量注册 :
index.js :
import focus from '@/directives/focus'
import copy from '@/directives/copy'
// 自定义指令
const directives = {
focus,
copy
}
export default {
install (Vue) {
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
}
}
- 在 main.js 中引入 index.js 并调用:
main.js :
import Vue from 'vue'
import App from './App'
import router from './router'
// 引入自定义指令
import Directives from '@/directives/index.js'
Vue.use(Directives)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
- 然后你在页面的任何地方就可以直接使用这些自定义指令了:
helloWorld.vue :
<input type="text" v-focus>
页面效果:
更多推荐
所有评论(0)