网站首页 > 技术文章 正文
1. 前言
本小节我们介绍 Vue 中的自定义指令。包括全局指令的注册、局部指令的注册、指令钩子函数的使用以及动态指令传参。其中,指令钩子函数和动态指令参数是本节的难点。
同学们需要充分理解每个指令钩子函数执行的时机、对动态指令参数多加练习才能对指令的使用得心应手。
2. 木子解释
Vue 除了提供了默认内置的指令外,还允许开发人员根据实际情况自定义指令,它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行底层操作的时候。 – 官方定义
在之前的章节中我们学习了指令 v-show,他的实现原理就是操作 DOM 元素的样式 display,使之实现隐藏、显示的效果。在日常开发中,我们经常把一些对 DOM 大量相同的操作封装成指令。学好指令可以给我们的开发带来便利、提高效率。同学们需要总结业务中的各种场景,多加练习。
3. 注册自定义指令
Vue 自定义指令和组件一样存在着全局注册和局部注册两种方式。全局注册的自定义指令可以在项目中的所有组件中使用,局部注册的指令只能在当前组件内部使用。接下来我们分步介绍全局指令和局部指令的注册方式。
3.1 全局注册
我们可以通过调用 Vue.directive 的方式来定义全局指令, 它接收两个参数:1. 指令名,2. 指令的钩子函数对象。 命名:
- 短横线:<my-directive>
- 驼峰式:<MyDirective> 使用驼峰命名指令时,首字母最好以大写字母开头。
钩子函数对象:指令的钩子函数对象我们将在下面段落 4 中详细介绍。
注意:注册指令时,指令名称不需要加 v- 前缀,默认是自动加上前缀的,使用指令的时候一定要加上 v- 前缀。
// 注册
// 驼峰命名
Vue.directive('MyDirective', {/* */})
// 短横线命名
Vue.directive('my-directive', {/* */})
// 使用
<div v-my-directive></div>
下面我们注册一个全局指令 v-focus,该指令的功能是在页面加载时,使得元素获得焦点。
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<label>姓名:</label>
<input id="name" v-focus type="text"/>
</div>
<div>
<label>年龄:</label>
<input id="age" type="text"/>
</div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
var vm = new Vue({
el: '#app',
data() {
return {}
}
})
</script>
</html>
"运行案例" 可查看在线运行效果
代码解释: JS 代码第 3-7 行,我们定义了指令 v-focus,定义 inserted 钩子函数,在节点被插入时获得焦点。 HTML 代码第 4 行,我们在 input 元素上使用指令,当页面打开时 id 为 name 的输入框会自动获取焦点。
3.2 局部注册
指令的局部注册和组件的局部注册类似,在实例的参数 options 中使用 directives 选项来注册局部指令,局部指令只能在当前这个实例中使用:
// 注册
// 短横线命名
{
directives: {
'my-directive': {
inserted: function (el) {
el.focus()
}
}
}
}
// 驼峰命名
{
directives: {
'MyDirective': {
inserted: function (el) {
el.focus()
}
}
}
}
// 使用
<div v-my-directive></div>
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<label>姓名:</label>
<input v-focus type="text"/>
</div>
<div>
<label>年龄:</label>
<input type="text"/>
</div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data() {
return {}
},
directives: {
focus: {
inserted: function (el) {
el.focus()
}
}
}
})
</script>
</html>
"运行案例" 可查看在线运行效果
代码解释: JS 代码第 8-14 行,我们定义了局部指令 v-focus,定义 inserted 钩子函数,在节点被插入时获得焦点。 HTML 代码第 4 行,我们在 input 元素上使用指令,当页面打开时 id 为 name 的输入框会自动获取焦点。
4. 钩子函数
上面我们介绍了 Vue.directive 第二个参数接收的是钩子函数对象,这些钩子函数都是可选的。接下来我们详细介绍这几个钩子函数的作用:
- bind:只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置;
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中);
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下);
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用;
- unbind:只调用一次,指令与元素解绑时调用。
4.1 钩子函数参数
指令钩子函数会被传入以下参数:
- el:指令所绑定的元素,可以用来直接操作 DOM ;
- binding:一个对象,包含以下属性:name:指令名,不包括 v- 前缀;value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2;oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用,无论值是否改变都可用;expression:字符串形式的指令表达式,例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1";arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
- vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情;
- oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
4.2 动态指令参数
指令的参数可以是动态的。例如,在 v-mydirective:[argument]=“value” 中,argument 参数可以根据组件实例数据进行更新!这使得自定义指令可以在应用中被灵活使用。
例如你想要创建一个自定义指令,用来改变页面元素的字体颜色。我们可以像这样创建一个通过指令值来更新字体颜色的自定义指令:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-color="color">Hello !</div>
<button @click="changeColor">切换颜色</button>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.directive('color', {
bind: function (el, binding, vnode) {
el.style.color = binding.value
},
update(el, binding) {
el.style.color = binding.value
}
})
var vm = new Vue({
el: '#app',
data() {
return {
color: 'red'
}
},
methods: {
changeColor() {
this.color = '#' + Math.floor( Math.random() * 0xffffff ).toString(16);
}
}
})
</script>
</html>
"运行案例" 可查看在线运行效果
代码解释: JS 代码第 3-10 行,我们定义了全局指令 v-color,定义 bind 钩子函数设置元素的字体颜色,定义 update 钩子函数,在节点更新时修改元素的字体颜色。 HTML 代码第 2 行,我们使用 v-color 指令,并动态传入值 color。 HTML 代码第 3 行,点击按钮切换 color 的值。 最终,当我们点击按钮时,“Hello !” 的字体颜色会随机变化。
上面的例子中我们通过指令动态设置了元素的字体颜色。但如果场景是我们需要修改元素的边框颜色又该怎么办呢?有些同学可能说我们可以再写一个 v-border-color 不就行了。那如果又有修改背景色的需求呢?这时使用动态参数就可以非常方便地根据每个组件实例来进行更新:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-color:[colorstyle]="color" style="border: 1px solid #ccc;">Hello !</div>
<div v-color:[borderstyle]="color" style="border: 1px solid #ccc;">Hello !</div>
<div v-color:[backgroundstyle]="color" style="border: 1px solid #ccc;">Hello !</div>
<button @click="changeColor">切换颜色</button>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.directive('color', {
bind: function (el, binding, vnode) {
var s = binding.arg
el.style[s] = binding.value
},
update(el, binding) {
var s = binding.arg
el.style[s] = binding.value
}
})
var vm = new Vue({
el: '#app',
data() {
return {
color: 'red',
colorstyle: 'color',
borderstyle: 'border-color',
backgroundstyle: 'background-color',
}
},
methods: {
changeColor() {
this.color = '#' + Math.floor( Math.random() * 0xffffff ).toString(16);
}
}
})
</script>
</html>
"运行案例" 可查看在线运行效果
代码解释: JS 代码第 3-12 行,我们定义了全局指令 v-color,定义 bind 钩子函数和 update 钩子函数。 HTML 代码第 2-4 行,我们使用 v-color 指令,并动态传入值 color。 HTML 代码第 5 行,点击按钮切换 color 的值。 最终,当我们点击 "切换颜色" 按钮时,分别会修改元素的 color、border-color、background-color 样式属性。
4.3 对象字面量
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式:
实例演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<div v-font="font">Hello !</div>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.directive('font', {
bind: function (el, binding, vnode) {
el.style.color = binding.value.color
el.style['font-size'] = binding.value.size
}
})
var vm = new Vue({
el: '#app',
data() {
return {
font: {
size: '26px',
color: 'red'
}
}
}
})
</script>
</html>
"运行案例" 可查看在线运行效果
代码解释: JS 代码第 3-8 行,我们定义了全局指令 v-font。 JS 代码第 13-16 行,我们定义了对象类型的值 font。 HTML 代码第 2 行,我们使用 v-font 指令,并动态传入对象类型的值 font。
5. 小结
本节,我们带大家学习了自定义指令在项目中的运用。主要知识点有以下几点:
- 使用 Vue.directive 注册全局组件。
- 使用 Vue 实例上 directives 属性注册局部组件。
- 使用指令中钩子函数操作 DOM 元素。
- 使用动态指令参数对 DOM 元素做不同的操作。
猜你喜欢
- 2024-10-21 Django 自定义管理命令:从入门到高级
- 2024-10-21 VUE自定义指令 自定义指令的应用场景有哪些?
- 2024-10-21 c4d自定义界面命令——把常用工具摆出来,工作效率大大提高
- 2024-10-21 Vue3.0 如何写自定义指令 vue自定义指令两种方式
- 2024-10-21 Vue学习之自定义指令 vue自定义指令和自定义组件
- 2024-10-21 权限应用-按钮权限标识利用自定义指令控制按钮
- 2024-10-21 关于Angularjs中自定义指令一些有价值的细节和技巧
- 2024-10-21 thinkphp自定义指令 thinkphp自定义错误页面
- 2024-10-21 TCL语言学习笔记(4) -自定义命令(过程/函数)和命名空间
- 2024-10-21 vue-12 自定义指令 vue自定义指令案例
你 发表评论:
欢迎- 11-18软考系统分析师知识点十六:系统实现与测试
- 11-18第16篇 软件工程(四)过程管理与测试管理
- 11-18编程|实例(分书问题)了解数据结构、算法(穷举、递归、回溯)
- 11-18算法-减治法
- 11-18笑疯了!巴基斯坦首金!没有技巧全是蛮力!解说:真远啊!笑死!
- 11-18搜索算法之深度优先、广度优先、约束条件、限界函数及相应算法
- 11-18游戏中的优化指的的是什么?
- 11-18算法-分治法
- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)