自定义指令
1、注册自定义指令
Vue.js提供了可以注册自定义指令的方法,通过不同的方法可以注册全局自定义指令和局部自定义指令。下面分别进行介绍。
1.1、全局自定义指令
通过应用程序实例的directive()方法可以注册一个全局自定义指令。该方法可以接收两个参数:指令ID和定义对象。指令ID是指令的唯一标识,定义对象是定义的指令的钩子函数。
例如,注册一个全局自定义指令,通过该指令实现页面加载后输入框获得焦点时选中输入框的全部内容。示例代码如下:
html
<div id="app">
请输入内容:<input v-select>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
}
}
});
vm.directive('select', {
//当被绑定的元素挂载到DOM中时执行
mounted: function(el) {
//元素获得焦点时内容全部选中
el.onfocus = ()=> {
el.select();
}
}
});
vm.mount('#app');
</script>

上述代码中,select是自定义指令ID,不包括v-前缀,mounted是指令定义对象中的钩子函数。该钩子函数表示,当被绑定元素挂载到DOM中且元素获得焦点时,选中元素的全部内容。在注册全局指令后,在被绑定元素中应用该指令即可实现相应的功能。
1.2、局部自定义指令
通过组件实例中的directives选项可以注册一个局部自定义指令。例如,注册一个局部自定义指令,通过该指令实现为元素添加样式的功能。示例代码如下:
html
<style>
.demo{
width: 300px;
height: 100px;
line-height: 100px;
text-align: center;
background-color: gray;
font-size: 30px;
color: white;
border: 3px solid blue;
}
</style>
<div id="app">
<div v-add-style="demo">
坚持不懈
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
demo: 'demo'
}
},
directives: {
addStyle: {
mounted: function(el, binding) {
el.className = binding.value;
}
}
}
}).mount('#app');
</script>

上述代码中,在注册自定义指令时采用了小驼峰命名的方式,将自定义指令ID定义为addStyle,而在元素中应用指令时的写法为v-add-style。在为自定义指令命名时建议采用小驼峰命名的方式。
2、钩子函数
在注册指令的时候,可以传入定义对象,对指令赋予一些特殊的功能。一个指令定义对象可以提供的钩子函数如表所示。
| 钩子函数 | 说明 |
|---|---|
beforeMount |
在指令第一次绑定到元素并且在挂载到DOM之前调用时,用这个钩子函数可以定义一个在绑定时执行一次的初始化设置 |
mounted |
在被绑定元素挂载到DOM时调用 |
beforeUpdate |
在指令所在组件的VNode更新之前调用 |
updated |
在指令所在组件的VNode及其子组件的VNode全部更新后调用 |
beforeUnmount |
在绑定元素的父组件卸载之前调用 |
unmounted |
只调用一次,在指令从元素上解绑且父组件已卸载时调用 |
这些钩子函数都是可选的。每个钩子函数都可以传入el、binding和vnode三个参数,beforeUpdate和updated钩子函数还可以传入oldVnode参数。这些参数的说明如下:
el:指令所绑定的元素,可以用来直接操作DOM。binding:一个对象,包含的属性如表所示。vnode:Vue编译生成的虚拟节点。oldVnode:上一个虚拟节点,仅在beforeUpdate和updated钩子函数中可用。
| 属性 | 说明 |
|---|---|
instance |
使用指令的组件的实例 |
value |
指令的绑定值,例如: v-my-directive="10",value的值是10 |
oldValue |
指令绑定的前一个值,仅在beforeUpdate和updated钩子函数中可用。无论值是否改变都可用 |
dir |
注册指令时作为参数传递的对象 |
arg |
传给指令的参数。例如:v-mydirective:tag,arg的值是"tag" |
modifiers |
一个包含修饰符的对象。例如:v-my-directibe.tag.bar,修饰符对象modifiers的值是{tag:true, bar:true} |
通过下面这个示例,可以更直观地了解钩子函数的参数和相关属性的使用。代码如下:
html
<div id="app">
<div v-demo:flag.m.n="message"></div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
message: '天才出于勤奋'
}
},
});
vm.directive('demo', {
mounted: function(el, binding, vnode) {
el.innerHTML = `instance:\t${JSON.stringify(binding.instance)}<br>
value:\t${binding.value}<br>
argument:\t${binding.arg}<br>
modifiers:\t${JSON.stringify(binding.modifiers)}<br>
vnode.keys:\t${Object.keys(vnode).join('.')}`
}
});
vm.mount('#app');
</script>

示例:设置图片宽度。
在页面中定义一张图片和一个文本框,在文本框中输入表示图片宽度的数字,实现为图片设置宽度的功能。代码如下:
html
<div id="app">
图片宽度:<input type="text" v-model="width">
<p>
<img src="images/1.jpg" v-set-width="width">
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
width: ''
}
},
directives: {
setWidth: {
updated: function(el, binding) {
el.style.width = binding.value + 'px';
}
}
}
});
vm.mount('#app');
</script>

有些时候,可能只需要使用mounted和updated钩子函数,这时可以直接传入一个函数代替定义对象。示例代码如下:
js
vm.directive('set-bgcolor', function (el, binding) {
el.style.backgroundColor = binding.value;
})
示例:为文字设置样式。
在页面中定义两个下拉菜单和一行文字,通过第一个下拉菜单为文字设置大小,通过第二个下拉菜单为文字设置颜色,代码如下:
html
<div id="app">
文字大小:<select v-model="obj.size">
<option value="">请选择</option>
<option value="20px">20px</option>
<option value="30px">30px</option>
<option value="40px">40px</option>
</select>
文字颜色:<select v-model="obj.color">
<option value="">请选择</option>
<option value="red">红色</option>
<option value="green">绿色</option>
<option value="blue">蓝色</option>
</select>
<p v-font-style="obj">宝剑锋从磨砺出,梅花香自苦寒来。</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
obj: {
size: '',
color: ''
}
}
},
directives: {
fontStyle: function(el, binding) {
el.style.fontSize = binding.value.size;
el.style.color = binding.value.color;
}
}
});
vm.mount('#app');
</script>

3、绑定值的类型
自定义指令的绑定值可以是data中的属性,还可以是任意合法的JavaScript表达式,如数值、字符串、对象字面量等。
3.1、绑定数值
自定义指令的绑定值可以是一个数值。例如,注册一个自定义指令,通过该指令设置定位元素的顶部位置,将该指令的绑定值设置为一个数值,该数值即为被绑定元素的顶部位置。示例代码如下:
html
<div id="app">
<span v-set-position="100">
Hello World
</span>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
}
},
directives: {
setPosition: function(el, binding) {
el.style.position = 'fixed';
el.style.top = binding.value + 'px';
}
}
});
vm.mount('#app');
</script>

3.2、绑定字符串
自定义指令的绑定值可以是一个字符串。将绑定值设置为字符串需要使用单引号。例如,注册一个自定义指令,通过该指令设置文字的粗细为粗体,将该指令的绑定值设置为字符串'bold',该字符串即为被绑定元素设置的样式。示例代码如下:
html
<div id="app">
<p v-set-style="'bold'">
Hello World
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
}
},
directives: {
setStyle: function(el, binding) {
el.style.fontWeight = binding.value;
}
}
});
vm.mount('#app');
</script>

3.3、绑定对象字面量
自定义指令的绑定值可以是一个JavaScript对象字面量。如果指令需要多个值,就可以使用这种形式。注意,此时对象字面量不需要使用单引号引起来。例如,注册一个自定义指令,通过该指令设置文本的大小、颜色和粗细,将该指令的绑定值设置为对象字面量。示例代码如下:
html
<div id="app">
<p v-set-style="{size: 20, color: 'blue', weight: 'bold'}">
Hello World
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
}
},
directives: {
setStyle: function(el, binding) {
el.style.fontSize = binding.value.size + 'px';
el.style.color = binding.value.color;
el.style.fontWeight = binding.value;
}
}
});
vm.mount('#app');
</script>
