第3章〓Vue.js指令
本章学习目标
通过本章的学习,能够理解Vue.js指令定义与分类,掌握Vue.js的内置指令使用方法,掌握自定义指令的注册方式,学会使用自定义指令实现相关工程项目的需要。
Web前端开发工程师应知应会以下内容:
理解Vue.js指令的定义与分类;
掌握条件渲染指令的使用与注意事项;
掌握列表渲染指令vfor的多种定义方法及与key属性配合使用的方法;
掌握数据绑定的多种方式;
掌握事件处理指令及事件修饰符的使用方法;
掌握其他内置指令的作用与使用方法;
掌握Vue自定义指令定义与注册的方法。
指令(Directive)本质是模板中出现的特殊符号,让处理模板的JavaScript库能够知道对相关的DOM元素进行一些相应的处理。Vue.js中的指令是以带前缀(v)的HTML属性(Attribute)的形式出现。指令是Vue给HTML标记新增的、拓展的属性,这些属性不属于标准的HTML属性,只有Vue.js认为是有效的,能够处理它。
指令的作用是当表达式的值改变时,将其产生的连带影响,响应式(Reactive)地作用于DOM上,也就是双向数据绑定。指令既可以用于普通标记,也可以用于标记。
Vue.js指令分为内置指令和自定义指令两种类型。Vue.js的指令是以v开头的。Vue提供的指令有vif、velse、velseif、vshow、vfor、vbind、von、vmodel、vtext、vhtml、vpre、vcloak、vonce等。
【基础语法】
Hello World
Hello Chu
…
【语法说明】
element表示标记名称; prefixdirectiveId表示通用的指令格式,如vif,v是前缀,if是指令ID; expression表示表达式。一些指令能够接受一个argument(参数),在指令名称之后以冒号表示。
指令的值是表达式,指令的值和文本插值表达式的写法是一样的。
3.1条件渲染
3.1.1vif/velse/velseif指令
vif指令用于条件性地渲染一块内容。当指令的表达式的值为true时,内容被渲染。
velse指令必须搭配vif使用,需要紧跟在vif或velseif后面,否则不起作用。可以用velse 指令给vif或velseif添加一个else块。
velseif指令充当vif的elseif块,可以链式地使用多次,以实现switch语句的功能。
【基本语法】
<标记名称 v-if="flag">v-if指令:当flag为真时,我被渲染!标记名称>
<标记名称v-else>v-else指令:当flag为假时,轮到我被渲染!标记名称>
<标记名称 v-if="expressionA">等级为优秀标记名称>
<标记名称 v-else-if="expressionB">等级为合格标记名称>
<标记名称 v-else>等级为不合格标记名称>
【语法说明】
vif指令必须赋值为逻辑值,为true时渲染,为false时不会渲染。与vif指令配套使用的velse指令不需要指定属性值,只需要给指定的标记添加此属性即可。条件渲染时,满足条件的标记才能被渲染出来,所以包含vif和velse指令的标记只能有一个被渲染。velseif指令与vif指令必须赋值,否则不会有效果。expressionA、expressionB表达式的值为逻辑值。
【例31】条件渲染综合应用。代码如下,页面效果如图31和图32所示。
1.
2.
3.
4.
5.
6.Vue条件渲染指令的应用
7.
8.
9.
10.条件渲染综合应用
11.
12.
13.
23.
24.
25.
33.
34.
35.
51.
52.
图31条件渲染综合应用初始渲染界面
图32单击按钮和改变成绩后渲染的界面效果
上述代码中,第15行使用von指令绑定click事件,调用change()方法,根据flag的值决定显示/隐藏第16行或第17行的标记的内容及第18~21行模板的内容; 第25~32行主要用于多分支ifelse结构,根据第28行文本输入框中输入的数值,将成绩分数转换为等级(优秀、合格、不合格)的形式。
3.1.2Vue 3.x中key值的应用
key值在Vue中是非常重要的,可以在DOM Diff中提高DOM的可复用性。那么,key值在Vue 2.x和Vue 3.x中的使用有什么不同呢?
(1) 在vif/velse/velseif指令中,key值绑定不再是必需的,因为Vue 3.x会自动生成对应的唯一key值。
(2) 若在Vue 3.x中(如vif)手动绑定key值,那么其他对应指令中(如velse)也必须手动绑定key值。
(3) 中的key值应该绑定在中,而不再绑定在它的子元素中。
1. vif/velseif/velse指令中的key值
在Vue 2.x中,推荐在vif/velseif/velse指令中绑定key值,格式如下。
Yes
No
但是,在Vue 3.x中,不再需要手动绑定key值,因为Vue 3.x会自动生成唯一的key值,格式如下。
Yes
No
如果在Vue 3.x中手动绑定了key值,那么每个分支都必须绑定唯一的key值,格式如下。
Yes
No
Yes
No
2. 标记使用vfor中的key值
在Vue 2.x中,标记不能绑定key值,而是绑定在它的子元素上,格式如下。
…
…
在Vue 3.x中,key值应该绑定在标记上,而不是它的子元素上,格式如下。
...
...
3. 和vif/velse/velseif一起使用的key值
在Vue 3.x中,如果使用了vfor指令,并且它的子元素中使用了vif/velseif/velse指令,那么key值也需要绑定在上,格式如下。
...
...
...
...
在Vue 2.x与Vue 3.x中使用key时,一定要注意使用场合,不能混淆,否则会报错。尤其需要注意vfor与vif/velseif/velse指令同时使用时,需要在不同的元素上使用。
【例32】使用key属性管理可复用的元素。代码如下,页面效果如图33和图34所示。
1.
2.
3.
4.
5.
6.Vue 3.x中key值的使用
7.
8.
9.
10.
11.
1.v-if/v-else
12.
13.
14.
15.
16.
17.
18.
19.
20.
2.template上v-for, 子元素上v-if/v-else
21.
22.
23.{{item}}
24.数组为空!
25.
26.
27.
28.
29.
30.
31.
50.
53.
54.
图33未单击按钮之前的初始页面
图34单击“切换显示”和“清空数组”按钮之后的页面效果
上述代码中,第12~19行定义两个模板,使用vif和velse指令切换使用用户名称、地址界面,不需要绑定key值; 第22行在模板上应用vfor指令,同时绑定key值,其内的子元素分别应用vif和velse指令; 第27行和第28行定义两个按钮,分别绑定change()和clear()方法,一个用于改变flag的值,另一个用于清空数组元素。
3.1.3vshow指令
vshow指令用于根据条件展示元素,从而实现元素的隐藏与显示。有vshow指令的元素始终会被渲染并保留在DOM中。
【基本语法】
<标记名称 v-show="true|false">标记的内容标记名称>
Hello!
【语法说明】
vshow的值是逻辑值,为true时渲染到页面上; 为false时不渲染到页面上。
带有vshow的元素始终会被渲染并保留在DOM中,vshow只是简单地切换元素的display CSS属性。
注意vshow不支持 标记,也不支持velse指令。
vshow与vif在使用上既有相同点,也有不同点。相同点是两者都是在判断DOM节点是否要显示。不同点如下。
(1) 实现方式不同。vif是根据属性值的真假判断直接从DOM树上删除或重建元素; vshow只是在修改元素的display属性值,无论vshow的值为何,元素始终在DOM树上。
(2) 编译过程不同。vif切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件侦听和子组件; vshow只是简单地基于CSS切换。
(3) 编译条件不同。vif是惰性的,如果初始条件为false,则什么也不做,只有在条件第1次变为true时才开始局部编译; vshow是在任何条件下(首次条件是否为true)都被编译,然后被缓存,而且DOM元素始终被保留。
(4) 性能消耗不同。vif有更高的切换消耗,不适合频繁的切换; vshow有更高的初始渲染消耗,适合频繁的切换。
【例33】vshow指令与vif指令使用比较。代码如下,页面效果如图35和图36所示。
1.
2.
3.
4.
5.
6.v-if与v-show指令应用区别
7.
8.
9.
10.
11.
条件为{{flag}}时,渲染'这是v-if'
12.
条件为{{flag}}时,渲染h3-这是v-show
13.
div
14.
15.
16.
29.
32.
33.
图35未单击按钮前页面效果
图36按钮单击后页面效果
上述代码中,第10~15行定义一个id为app的标记,其内包含一个按钮、两个
和一个。第14行定义一个按钮,侦听click事件,绑定change()方法,用于改变flag的值。分别使用vif和vshow指令用于切换3个标记是否被渲染并显示,vif和vshow的属性值均为flag。当flag值为true时,3个标记都一起被渲染并显示在页面上,如图35所示。当flag值为false时,第1个
不会被渲染,而其他、标记一起被渲染,但由于CSS属性display: none,所以不显示在页面上,如图36所示。
3.2列表渲染(vfor指令)
可以用vfor指令基于一个数组渲染一个列表。vfor指令可以使用item in|of items形式的特殊语法,其中items是源数据数组(可以是普通数组或对象数组),而item则是被迭代的数组元素的别名。vfor指令的值中可以使用关键字in或of。符号|表示或的意思。
1. 使用单一参数的vfor指令循环遍历对象数组
【基本语法】
【语法说明】
定义数组类型的数据items,数组中每个元素有3个属性,分别是bookName、isbn、author,用vfor指令对
标记循环遍历渲染,如图37所示。
图37使用单一参数的vfor指令循环遍历对象数组
从图37可以看出,对象中的属性并没有分项列出,而是一次性列出。可以使用带3个参数的vfor指令的形式遍历对象数组。
2. 使用两个参数的vfor指令循环遍历对象数组
【基本语法】
-
{{index+1}}-{{item.bookName}}-{{item.issn}}-{{item.author}}
【语法说明】
vfor属性值中支持第2个参数index,作为当前项的索引。index不可以放在第1个参数位置上,否则渲染后不会出结果。多个参数必须使用括号包裹,并使用逗号分隔参数。依次访问数组中对象的属性item.bookName、item.issn、item.author,结果如图38所示。
图38使用两个参数的vfor指令循环遍历对象数组
3. 使用3个参数的vfor指令循环遍历对象的属性
vfor指令也可以对对象的属性进行遍历,使用(value,key,index) in student的形式遍历数组元素。
【基本语法】
- {{index}}-{{key}}-{{value}}
【语法说明】
student是一个对象,它有3个属性,分别为name、class、age。采用vfor指令分别遍历对象的每个属性。3个参数的位置顺序可以任意排列,默认第1个参数为value,第2个参数为key,第3个参数为index,结果如图39所示。
图39使用3个参数的vfor指令循环遍历对象的属性
4. vfor指令循环遍历普通数组
【基本语法】
在data选项中增加定义普通数组array,格式如下。
array: [100, 200, 300, 205, 110, 96],
【语法说明】
array为普通数组,可以使用单一参数和带第2个参数(index)的vfor指令遍历普通数组元素,结果如图310所示。
图310vfor指令循环遍历普通数组
5. vfor指令循环遍历某一范围内的整数
【基本语法】
{{count}}
【语法说明】
使用vfor指令遍历某一范围内的整数,count表示20以内的每个整数,然后在一行中输出所有整数,结果如图311所示。
图311vfor指令循环遍历某一范围内的整数
6. vfor指令使用key关键字循环遍历数组
【基本语法】
{{user.id}}--{{user.name}}
在data选项中增加下列属性定义。
data(){
return{
students: [{id:1,name:'张开民'}],
id:'',
name:''
}
},
【语法说明】
段落标记绑定key属性,使段落
标记唯一被渲染。采用vfor指令遍历数组。
【例34】vfor指令的综合应用。代码如下,页面效果如图312所示。
1.
2.
3.
4.
5.
6.列表渲染v-for指令的应用
7.
8.
9.
10.
11.
19.
23.
31.
37.
48.
49.
95.
98.
99.
图312vfor指令的综合应用
7. vfor与vif指令的执行优先级
当vfor与vif指令一起使用时,即当它们处于同一节中,vfor具有比vif更高的优先级,这意味着vif将分别重复运行于每个vfor循环中。所以,不推荐vfor和vif指令同时使用。
针对下列两种常见的情况,建议采用的做法如下。
为了过滤一个列表中的项目(如vfor="user in users" vif="user.isActive"),在这种情况下,请将users替换为一个计算属性(如activeUsers),让其返回过滤后的列表。
为了避免渲染本应该被隐藏的列表(如vfor="user in users" vif="isDisplayUsers"),在这种情况下,请将vif移动至容器元素上(如、)。
在Vue 3.x中,将vfor和vif指令同时作用在同一个元素上会报错。在Vue 2.x中可以,但不建议这么做。在父元素上使用vfor指令,在子元素上使用vif指令,结果如图313所示。
通常做法:v-for与v-if同时作用于同一元素上,显示活跃用户
-
{{user.id}}:{{ user.name }}--状态:{{user.isActive}}
<-- 建议做法:v-for与v-if分别作用于不同元素上,显示活跃用户 -->
-
{{user.id}}:{{ user.name }}--状态:{{user.isActive}}
图313vfor与vif分别作用在不同元素上
【例35】vfor与vif指令配合使用的解决方案。代码如下,页面效果如图314所示。
图314vfor与vif配合使用页面效果
1.
2.
3.
4.
5.
6.v-for与v-if指令配合应用场景
7.
8.
9.
10.
11.
建议做法:v-for与v-if不在同一元素上,显示活跃用户
12.
13.-
14.{{user.id}}:{{ user.name }}--状态:{{user.isActive}}
15.
16.
17.
最佳方法:v-for与v-if不同时用在一个元素上,显示所示用户
18.
19.-
20.{{user.id}}:{{ user.name }}--状态:{{user.isActive}}
21.
22.
23.
最佳方法:v-for与v-if不同时用在一个元素上,仅显示活跃用户
24.
25.-
26.{{user.id}}:{{ user.name }}--状态:{{user.isActive}}
27.
28.
29.
30.
55.
56.
3.3类与样式绑定(vbind指令)
vbind指令用于动态地、响应地更新HTML属性,从而实现与class、style属性的绑定。只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将vbind指令用于class和style属性时,Vue.js做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
通常可以将vbind:attribute形式缩写为:attribute形式,将von:event形式缩写为@event形式,这种形式称为“语法糖”。所谓“语法糖”,是指在不影响功能的情况下,添加某种方法实现同样的效果,从而方便程序开发,因此使用语法糖可以简化代码书写。
【基本语法】
(1) HTML中定义如下。
(2) vbind:class指令也可以与普通的class属性共存。
对象
style数组
//组件的data选项定义
data(){
return{
classObject: {'class-a': true, 'class-b': false},
isActive: true,
hasError: false,
classA: 'class-a',
classB: 'class-b',
styleObjectA:{ color:'blue'},
styleObjectB:{ background:'#DFDFDF'},
}
}
【语法说明】
vbind可以绑定class属性,也可以绑定style属性。需要将vbind绑定到特定的元素上,从而动态地渲染元素的样式。其中,与class属性绑定时,其值可以是变通变量、对象、数组等; 与style属性绑定时,其值可以为对象、数组。
在实际工程中需要分3步实现。
(1) 在HTML元素上完成属性绑定,并定义其值的类型。
(2) 在Vue组件的data选项中定义相关属性的值。
(3) 在CSS部分需要定义相关类的样式。
【例36】class和style绑定综合应用。代码如下,页面效果如图315所示。
图315class和style绑定综合应用
1.
2.
3.
4.
5.
6.class与style绑定实战
7.
8.
16.
17.
18.
19.
27.
28.
34.
35.
55.
56.
3.4事件处理(von指令)
von指令(简写为 @)主要用来侦听DOM事件,并在触发时执行对应的JavaScript。用法: von:click="methodName" 或 @click="handler"。
事件处理器的值如下。
(1) 内联事件处理器: 事件被触发时执行的内联 JavaScript 语句 (与onclick类似)。
(2) 方法事件处理器: 一个指向组件上定义的方法的属性名或路径。
1. 内联事件处理器
内联事件处理器通常用于简单场景,举例如下。
// 单文件组件中, 采用组合式API(选项式API中使用methods)
const count = ref(0)
Count is: {{ count }}
2. 方法事件处理器
随着事件处理器的逻辑变得越来越复杂,内联代码方式变得不够灵活。因此,von指令也可以接受一个方法名或对某个方法的调用,举例如下。
// 在单文件组件中, 采用组合式API(选项式API中使用methods)
const name = ref('Vue.js')
function greet(event) {
alert(`Hello ${name.value}!`)
// event 是 DOM 原生事件
if (event) {
alert(event.target.tagName)
}
}
方法事件处理器会自动接受原生DOM事件并触发执行。在上面的例子中,能够通过被触发事件的event.target.tagName访问到该 DOM元素。
3. 方法与内联事件判断
模板编译器会通过检查von指令的值是否是合法的JavaScript标识符或属性访问路径断定是何种形式的事件处理器。举例来说,foo、foo.bar和foo['bar']会被视为方法事件处理器,而foo()和count++会被视为内联事件处理器。
4. 在内联处理器中调用方法
除了直接绑定方法名,还可以在内联事件处理器中调用方法,并允许向方法传入自定义参数以代替原生事件。举例如下。
// 在单文件组件中采用组合式API(选项式API中使用methods)
function say(message) {
alert(message)
}
5. 在内联事件处理器中访问事件参数
有时我们需要在内联事件处理器中访问原生DOM事件。可以向该处理器方法传入一个特殊的$event变量,或者使用内联箭头函数,举例如下。
function warn(message, event) {
// 这里可以访问原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
von指令绑定事件处理函数可以带参数,也可以不带参数。使用时需要注意以下3点。
(1) 普通方法。不使用圆括号,event被自动当作实参传入。
(2) 内联处理器中的方法,即方法中调用其他的方法,如JavaScript原生方法(如阻止冒泡)、自定义的方法。使用圆括号,必须显式地传入event对象。Vue提供了一个特殊变量$event,用于访问原生DOM事件。
(3) von指令可以使用语法糖简写,格式为@click,等同于von:click。
【例37】von指令综合应用。代码如下,页面效果如图316所示。
图316von指令综合应用
1.
2.
3.
4.
5.
6.
事件侦听实战
7.
8.
9.
10.
11.
v-on属性值为一般表达式:计数器为{{count}}
12.
13.
v-on属性值为方法:当前系统日期为{{now}}
14.
15.
v-on属性值为带参数的方法:产生6个随机区间的整数
16.
{{numArr}}
17.
20.
v-on属性值为带$event的方法:访问原生的event对象为{{information}}
21.
24.
v-on属性值不带参数的方法:默认传入event,类型为{{typeObject}}
25.
26.
27.
65.
66.
上述代码中,第17行von指令绑定带参数的事件处理方法createRndNum6(100,300),随机产生6个[100,300]的整数; 第21行von指令绑定带参数的事件处理方法showInfo1('用$event传入!',$event),传入特殊变量$event,用于访问原生DOM事件; 第25行von指令绑定不带参数的事件处理方法showInfo2(),在methods(function)中定义时需要将event作为参数。
6. 事件修饰符
在处理事件时调用event.preventDefault()或event.stopPropagation()方法是很常见的。尽管可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理DOM事件的细节会更好。
为解决这一问题,Vue为von指令提供了事件修饰符(Modifier)。修饰符是用.表示的指令后缀。Vue中的事件修饰符主要如下。
(1) .stop: 等同于JavaScript中的event.stopPropagation()方法,防止事件冒泡。
(2) .prevent: 等同于JavaScript中的event.preventDefault()方法,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)。
(3) .capture: 与事件冒泡的方向相反,事件捕获由外到内。
(4) .self: 只会触发自己范围内的事件,不包含子元素。
(5) .once: 只会触发一次。
(6) .passive: 不检查是否默认事件被阻止,用于触发滚动时性能会更好。
下面分别介绍每个修饰符的作用。
...
注意使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此,使用@click.prevent.self会阻止元素及其子元素的所有单击事件的默认行为,而@click.self.prevent则只会阻止对元素本身的单击事件的默认行为。
.capture、.once和.passive修饰符与原生的addEventListener事件相对应。
...
...
.passive修饰符一般用于触摸事件的侦听器,可以用来改善移动端设备的滚屏性能。
注意请勿同时使用.passive和.prevent修饰符,因为.passive已经向浏览器表明了不想阻止事件的默认行为。如果这么做了,则.prevent会被忽略,并且浏览器会抛出警告。
【例38】事件修饰符综合应用。代码如下,页面效果如图317所示。
图317事件修饰符综合应用
1.
2.
3.
4.
5.
6.
事件修饰符综合应用
7.
8.
9.
10.
11.
事件修饰符综合应用
12.
13.
div1
14.
15.
17.
教育网(默认行为阻止)
18.
19.
教育网(默认行为允许)
20.
24.
25.
27.
28.
Vue.js 是什么
29.
Vue是一款用于构建用户界面的 JavaScript 框架。它基于标准HTML、CSS和JavaScript构建,并提供了一套声明式的、组件化的编程模型,帮助用户高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。
30.
31.
滚动 {{scrollCount}} 次。
32.
33.
34.
35.
64.
69.
70.
7. 按键修饰符
在侦听键盘事件时,经常需要检查详细的按键。Vue允许为 von或@在侦听键盘事件时添加按键修饰符。
可以直接使用KeyboardEvent.key暴露的按键名称作为修饰符,但需要转为kebabcase形式。
在上面的例子中,仅会在$event.key为'PageDown'时调用事件处理。
1) 按键别名
Vue.js提供了按键别名,也称为快捷名称,如表31所示。
表31按键快捷名称
序号快 捷 名 称描述序号快 捷 名 称描述
1.enterEnter键7.down↓键
2.tabTab键8.left←键
3.delete删除和退格键9.right→键
4.escEsc键10.ctrlCtrl键
5.space空格键11.altAlt键
6.up↑键12.shiftShift键
根据按键的快捷名称,可以对按钮事件增加修饰符,代码如下。
2) 系统按键修饰符
可以使用系统按键修饰符触发鼠标或键盘事件侦听器,只有当按键被按下时才会触发。系统按键修饰符有.ctrl、.alt、.shift、.meta。
注意在Mac键盘上,meta是Command键(); 在Windows键盘上,meta是Windows键(); 在Sun微机系统键盘上,meta是钻石键(◆)。在某些键盘上,特别是MIT和Lisp机器的键盘及其后代版本的键盘,如Knight键盘、spacecadet键盘,meta都被标记为META。在 Symbolics键盘上,meta也被标记为META或Meta。
举例如下。
Do something
注意系统按键修饰符和常规按键不同。与keyup事件一起使用时,该按键必须在事件发生时处于按下状态。换句话说,keyup.ctrl只会在仍然按住Ctrl键但松开了另一个键时被触发。若单独松开Ctrl键,将不会触发。
3) .exact修饰符
.exact修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。
4) 鼠标按键修饰符
鼠标按键修饰符有.left、.righ、.middle,这些修饰符将处理程序限定为由特定鼠标按键触发的事件。
【例39】按键修饰符的应用。代码如下,页面效果如图318所示。
图318按键修饰符的应用
1.
2.
3.
4.
5.
6.
按键修饰符的应用
7.
8.
9.
10.
11.
16.
21.
您的信息:{{myInformation}}
22.
27.
28.
61.
65.
66.
3.5表单输入绑定(vmodel指令)
在Vue.js中可以通过vmodel指令在表单的input、textarea及select元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法更新元素。尽管有些神奇,但vmodel指令本质上不过是语法糖。它负责侦听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
vmodel指令会忽略所有表单元素的value、checked、selected属性的初始值,而总是将Vue实例或组件的数据作为数据来源。程序设计人员可以通过JavaScript在组件的data选项中声明初始值。
vmodel在内部为不同的输入元素使用不同的属性并抛出不同的事件。
(1) 文本输入框和多行文本域元素使用value属性和input事件。
(2) 复选框和单选按钮使用checked属性和change事件。
(3) 下拉列表框将value作为prop,并将change作为事件。
注意对于需要使用输入法(如中文、日文、韩文等) 的语言,vmodel指令不会在输入法组合文字的过程中得到更新。如果需要处理这个过程,可使用input事件。
【基本语法】
Checked names: {{ checkedNames }}
男
女
【语法说明】
在多行文本区域插值()并不会生效,应用vmodel代替。
单个复选框,绑定到布尔值; 多个复选框,绑定到同一个数组,同时给每个复选框设置不同的id值和value值。选择的结果将返回到数组中。
要实现一组单选按钮互斥的功能,就需要vmodel配合value使用。给一组单选按钮设置不同的id值和不同的value值,vmodel绑定同一个数据变量。
在下拉列表框中,如果vmodel表达式的初始值未能匹配任何选项,select元素将被渲染为“未选中”状态。在iOS中,容易造成用户无法选择第1个选项。因为在此情况下,iOS不会触发change事件。因此,推荐像上面这样提供一个值为空的禁用选项。若下拉列表支持多选,请将vmodel绑定到数组上,与复选框多选类似。
【例310】表单绑定的综合应用。代码如下,页面效果如图319所示。
1.
2.
3.
4.
5.
6.v-model绑定表单
7.
8.
11.
12.
13.
42.
56.
57.
图319表单绑定的综合应用
上述代码中,第22~28行定义一组复选框,用于选择兴趣与爱好,分别为3个复选框定义不同的id和value,使用vmodel指令绑定同一checkMyLove数组,用于存放用户选择的选项; 第30行和第31行定义一组单选按钮,为每个单选按钮定义不同的id和value,并通过vmodel指令绑定sex属性,sex的值为选中的单选按钮的value; 第33~39行定义下拉列表框,用于显示选择的专业选修课,支持多选,通过vmodel指令绑定mySelected数组(若为单选,可以设为简单变量),其值为选中选项的value。
【例311】下拉列表框选项自动渲染。代码如下,页面效果如图320所示。
图320下拉列表框选项自动渲染
1.
2.
3.
4.
5.
6.下拉列表框选项自动渲染
7.
8.
9.
10.
11.
专业核心课程选择:{{mySelected}}
12.
17.
18.
33.
34.
1. 表单元素值绑定
对于单选按钮、复选框及下拉列表框的选项,vmodel指令绑定的值通常是静态字符串或布尔值。但是,有时需要把值绑定到Vue组件或实例的一个动态属性上,就可以用vbind指令实现,并且这个属性的值可以不是字符串。
【基本语法】
//以下需要在Vue组件或实例中的data选项中定义
myChecked1:'',
myChecked2:'',
mySelected: '',
myRadio: '',
radio1: '123',
valueA: "A",
valueB: "B",
【语法说明】
当选中第1个单选按钮时,myRadio的值为字符串"radio"; 当选中第2个单选按钮时,myRadio的值为字符串"123"。当选中第1 个复选框时,myChecked1为true,否则为false; 当选中第2 个复选框时,myChecked2为"A"(动态绑定数据属性)。当选中下拉列表框中第1个选项时,mySelected为字符串 "html"; 当选中下拉列表框中第2个选项时,mySelected为对象{valueC: 'js'}。具体代码参见例312。
【例312】表单元素值绑定。代码如下,页面效果如图321所示。
1.
2.
3.
4.
5.
6.表单元素值绑定
7.
8.
9.
10.
32.
48.
49.
图321表单元素值绑定
2. vmodel修饰符
vmodel指令的修饰符一般用于控制数据同步的时机。Vue内置的vmodel指令修饰符如表32所示。
表32vmodel指令修饰符
修 饰 符描述
.trim自动过滤输入内容最开始和最后的空格,中间会保留一个空格,多的会被过滤掉
.number自动将输入的数据转换为number类型
.lazy一般情况下,在input上使用vmodel指令会一直同步输入的内容与显示的内容,不过添加.lazy后,就会变成在失去焦点或按Enter键时才更新数据
【基本语法】
【语法说明】
vmodel.lazy修饰符表示在输入域失去焦点或按Enter键时数据才更新; vmodel.number修饰符表示将输入域中内容转换为数值型数据; vmodel.trim修饰符表示将输入域中内容的前后空格过滤掉,并将字符串中间的多个空格转换为一个空格。
【例313】vmodel修饰符的应用。代码如下,页面效果如图322和图323所示。
图322vmodel修饰符的应用 (初始页面)
图323vmodel修饰符的应用 (输入信息页面)
1.
2.
3.
4.
5.
6.v-model修饰符的应用
7.
8.
9.
10.
20.
32.
33.
上述代码中,第13 行文本框使用了vmodel.lazy修饰符,输入姓名时不会在第17行的标记内立即更新,而是等待姓名完全输入结束后才更新; 第14行文本框使用了vmodel.number修饰符,会将文本框输入的字符串型数据转换为数值型数据,并在第17行
标记中显示学号和类型; 第15行使用了vmodel.trim修饰符,将用户输入的建议的开头和结束处多余的空格全部删除,并将字符串中间输入的多个空格变成一个空格。
3.6vhtml与vtext指令
当网速很慢或JavaScript出错时,会暴露{{message}}。因此,推荐使用vtext指令,可以很好地解决这个问题。为了输出真正的HTML,可以使用vhtml指令。
【基本语法】
{{myText}}
【语法说明】
vtext指令更新元素的textContent属性。可以读取文本,但不能读取标记,解析为文本。如果要更新部分的textContent值发生改变,插值处的内容也会随之更新。
vhtml指令更新元素的innerHTML属性。可以读取标记,解析出标记。它与vtext指令的区别在于vtext输出的是纯文本,浏览器不会对其再进行HTML解析,但vhtml指令会将其解析为标记后输出。
注意在正式环境中动态渲染HTML是很危险的,因为容易受到XSS攻击。
【例314】vtext与vhtml指令比较应用。代码如下,页面效果如图324所示。
1.
2.
3.
4.
5.
6.v-text和v-html指令的应用
7.
8.
9.
10.
11.
17.
23.
24.
35.
36.
图324vtext与vhtml指令比较应用
3.7vonce、vcloak、vpre指令
【基本语法】
v-once:{{myInput}}
{{information}}
{{message}}
【语法说明】
vonce指令: 只执行一次DOM渲染,渲染完成后视为静态内容,跳出以后的渲染过程。
vpre指令: 在模板中跳过Vue的编译,直接输出原始值。这时并不会输出message值,而是直接在网页中显示{{message}}。
vcloak指令: 保持在元素上直到关联实例结束编译。和CSS规则([vcloak]{display: none;})一起使用时,这个指令可以隐藏未编译的{{information}},直到实例准备完毕。渲染时会出现变量闪烁。
【例315】vpre、vonce、vcloak指令综合应用。代码如下,页面效果如图325所示。
图325vonce、vcloak、vpre指令综合应用
1.
2.
3.
4.
5.
6.v-pre、v-once及v-cloak指令的应用
7.
10.
11.
12.
13.
14.
20.
27.
28.
39.
40.
上述代码中,第25行使用vcloak指令消除页面内闪烁,配合CSS样式,实现当{{information}}未渲染完成时隐藏,当渲染结束时显示。实际上效果未体现。
3.8Vue.js自定义指令
除了Vue内置的一系列指令(如vmodel或vshow)之外,Vue还允许注册自定义的指令 (Custom Directives)。Vue中重用代码的方式有组件和组合式函数。组件是主要的构建模块,而组合式函数则侧重于有状态的逻辑。另外,自定义指令主要是为了重用涉及普通元素的底层DOM访问的逻辑。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接受指令所绑定元素作为其参数。下面是一个自定义指令的例子,当一个input元素被Vue插入DOM中后,它会被自动聚焦,代码如下。
// 组件中JS部分
const focus = {
mounted: (el) => el.focus()// 使用箭头函数定义
}
export default {
directives: {// 组件内局部注册
// 在模板中启用 v-focus
focus
}
}
将一个自定义指令全局注册到应用层级也是一种常见的做法,代码如下。
const app = Vue.createApp({})
// 使 v-focus 在所有组件中都可用
app.directive('focus', {
/* …*/
})
3.8.1自定义指令注册
【基本语法】
<标记名称 v-my-directive>使用方式与内置指令相同标记名称>
(1) 注册全局自定义指令vmydirective。第1种定义方法如下。
const app=Vue.createApp({});
app.directive('my-directive', {
// 生命周期钩子函数
})
第2种定义方法如下。
app.directive('my-directive', function(el, binding, vnode){}),
// 其中el为DOM,vnode为Vue的虚拟DOM,binding为一个较复杂的对象
// 使用箭头函数的形式定义
app.directive("color", (el, binding) => {
// 这会在 mounted 和 updated 时都调用
el.style.color = binding.value;
console.log(el.style.color);
});
(2) 注册局部自定义指令mydirective。在组件内使用directives选项定义,代码如下。
directives: {
my-directive: { }// 包含生命周期钩子的指令对象
}
(3) 指令钩子函数。
一个指令的定义对象可以提供几种钩子函数,包括created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、unmounted,不过它们都是可选的,定义如下。
const myDirective = {
// 在绑定元素的属性前或事件监听器应用前调用
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) {}
}
【语法说明】
指令注册方式分为全局注册和局部注册。使用组件的directives选项定义的指令称为局部自定义指令,使用Vue.createApp({}).directive()或app.directive()方法定义的指令称为全局自定义指令。另外,定义的指令不支持驼峰式(如myDirective)写法。
在使用时,钩子函数也会传入以下参数。
(1) el: 指令所绑定的元素,可以用来直接操作DOM。
(2) binding: 一个对象,包含以下属性。
value: 传递给指令的值,如vmydirective="1*3"中,绑定值为3。
oldValue: 之前的值,仅在beforeUpdate和updated中可用。无论值是否更改,它都可用。
arg: 传递给指令的参数(如果有的话),如在vmydirective:foo中,参数是"foo"。
modifiers: 一个包含修饰符的对象(如果有的话)。例如,在vmydirective.foo.bar中,修饰符对象是{foo: true,bar: true}。
instance: 使用该指令的组件实例。
dir: 指令的定义对象。
(3) vnode: 代表绑定元素的底层VNode。
(4) prevNode: 之前的渲染中代表指令所绑定元素的VNode。仅在beforeUpdate和updated中可用。
举例来说,像下面这样使用指令:
binding参数会是一个这样的对象:
{
arg: 'foo',
modifiers: { bar: true },
value: /* baz 的值 */,
oldValue: /* 上一次更新时 baz 的值 */
}
自定义指令的参数也可以是动态的。在vmydirective:[argument]="value"中,argument参数可以根据组件实例数据进行更新。这使得自定义指令可以在应用中被灵活使用。
例如,以下指令的参数会基于组件的arg数据属性响应式地更新。
注意除了el外,其他参数都是只读的,不要更改它们。若需要在不同的钩子间共享信息,推荐通过元素的dataset属性实现。
对于自定义指令,一个很常见的情况是仅仅需要在 mounted 和 updated钩子上实现相同的行为,除此之外并不需要其他钩子。这种情况下可以直接用一个函数定义指令。
// JS部分
app.directive('color', (el, binding) => {
// 默认会在 mounted 和 updated 时都调用
el.style.color binding.value="red"//颜色可以是英文名、十六进制或RGB等
})
【例316】自定义指令。设计要求: ①采用全局注册方式定义元素自动获得焦点的vfocus指令; ②采用局部注册方式定义随机改变元素的背景颜色的vcolor指令。代码如下,页面效果如图326所示。
图326自定义指令
1.
2.
3.
4.
5.
6.
自定义指令全局注册与局部注册的应用
7.
8.
9.
10.
18.
52.
53.
上述代码中,第14行使用自定义全局指令vfocus实现绑定元素自动获得焦点; 第15行使用自定义局部指令vcolor实现绑定的元素自动随机添加背景颜色; 第19~39行定义Vue组件App,并在其中局部注册vcolor指令,实现绑定元素随机改变背景颜色; 第42~49行全局注册自定义指令vfocus,当元素挂载到DOM时,实现自动获得焦点。
3.8.2对象字面量
在计算机科学中,字面量(Literal)是用于表达源代码中一个固定值的表示法(Notation)。字面量表示如何表达这个值,一般除去表达式,给变量赋值时,等号右边都可以认为是字面量。字面量分为字符串字面量(String Literal)、数组字面量(Array Literal)和对象字面量(Object Literal),另外还有函数字面量(Function Literal)。
对象字面量是封闭在花括号对({})中的一个对象的零个或多个“属性名:值”列表。
若自定义指令需要多个值,可以传入一个JavaScript对象字面量。指令可以使用任意合法的JavaScript 表达式。
app.directive('my-directive', (el,binding) => {
console.log(binding.value.color)// "red"
console.log(binding.value.text)// " Vue简单易学!"
})
当在组件上使用自定义指令时,它会始终应用于组件的根节点,和透传Attributes类似。
My component content
注意组件可能含有多个根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和attribute不同,指令不能通过vbind="$attrs"传递给一个不同的元素。总的来说,不推荐在组件上使用自定义指令。
【例317】自定义指令钩子函数与动态参数实战。设计要求: ①采用全局注册方式定义元素特定样式的vblackbold指令,样式效果为“加粗,黑色,1px黑色虚线边框”; ②输出主要钩子函数的相关参数和值; ③定义全局自定义指令vmovetop,功能是通过固定布局方式将元素固定在离顶部一定像素的位置上; ④定义全局自定义指令vmove,功能是通过固定布局方式将元素固定在离顶部或左边一定像素的位置上。代码如下,页面效果如图327和图328所示。
1.
2.
3.
4.
5.
6.
钩子函数参数与动态参数的应用
7.
8.
9.
10.
11.
16.
22.
26.
27.
66.
72.
73.
图327自定义指令综合应用(初始页面)
上述代码中,第18行定义文本输入框,使用vmodel指令绑定valueA,单击微调按钮触发数据更新; 第24行使用自定义全局指令vblackbold实现绑定元素特定样式(黑色,加粗),元素渲染结果如图327所示; 第44~52行全局注册自定义指令vblackbold,其中第47行实现绑定元素的边框样式为“1px dashed #000000'”,第48~51行输出钩子函数相关参数和值; 第53~57行使用全局注册方式自定义vmovetop指令,该指令实现绑定元素采用固定布局方式,从顶部向下移动valueA像素; 第14行使用自定义指令vmove,并设置动态参数[direction],绑定valueA,动态参数可以赋值为left或top,默认为left,该元素向右移valueA像素; 第58~63行全局注册vmove指令,根据动态参数决定实现该元素以固定布局方式、有边框效果、左移/右移valueA像素。当对象的属性以变量的形式出现时,通常使用数组的方式(如代码第62行)设置或返回对象的属性值。当单击“改变方向”按钮时,改变direction(默认为left,单击后为top)。此时灰色段落移动方向改为上下移动,如图328所示。其中3个自定义指令会在mounted和updated钩子函数中调用。
图328自定义指令综合应用(操作页面)
本章小结
本章主要介绍了Vue.js指令的定义与指令分类,重点介绍了指令的注册方式。
Vue.js指令分为内置指令与自定义指令。指令注册方式分为全局注册与局部注册。
Vue.js内置指令主要有条件渲染指令(vif、velseif、velse、vshow)、列表渲染指令(vfor)、类与样式绑定指令(vbind)、事件处理指令(von)、表单输入绑定指令(vmodel)、输出元素内容指令(vtext)、输出元素内HTML指令(vhtml)、隐藏元素指令(vcloak)、原样输出元素内容指令(vpre)、只执行一次指令(vonce)。事件修饰符有.stop、.prevent、.capture、.self、.passive、.once。vmodel指令有修饰符,分别为.trim、.lazy、.number。键盘事件也可以设置按键修饰符。
Vue.js自定义指令主要是对Vue.js内置指令功能的补充。自定义指令使用app.directive()方法进行全局注册。定义时根据需要选择不同的钩子函数,有created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、unmounted。要求熟练地使用相关参数,主要参数有el、binding、vnode、prevNode,其中binding是一个复杂的对象,包含value、oldValue、arg、modifiers、instance、dir等属性。
Vue.js自定义指令还支持动态参数,格式为vmydirective:[argument]="value",argument参数可以根据组件实例数据进行更新。
扫一扫
自测题
练习3
1. 选择题
(1) 下列选项中,采用语法糖绑定href属性的是()。
A. vbind:href='ref2'B. von:click='addOne'
C. @href='ref3'D. :href='href1'
(2) 下列选项中,在输入框中输入内容后按Enter键的按键修饰符是()。
A. .tabB. .enterC. .ctrlD. .shift
(3) 下列选项中,能够防止执行预设的行为的事件修饰符是()。
A. .preventB. .captureC. .stopD. .passive
(4) 下列vmodel修饰符中,能够在输入结束失去焦点或按Enter键时才更新数据的是()。
A. .numberB. .trimC. .lazyD. 所有选项都是
(5) 下列选项中,能够解析为HTML代码,并且显示相关标记的样式效果的是()。
A. vbindB. vhtmlC. vtextD. vpre
(6) 下列选项中,能够将标记的内容原样输出的指令是()。
A. vpreB. vhtmlC. vonceD. von:click.once
(7) 下列选项中,能够进行事件处理的指令是()。
A. vforB. von:click(@ click)
C. vifD. vmodel
(8) 下列选项中,能够进行表单输入绑定的指令是()。
A. vhtmlB. vbindC. vmodelD. vcloak
2. 填空题
(1) Vue.js中条件渲染指令有vif、、velse和。
(2) Vue组件中定义数据选项data为形式,其中定义的“属性/值”对,必须出来,才能正确提供响应式数据。
(3) 显示标记的样式效果和内容的指令是; 仅作为纯属文本输出内容的指令是; 能够渲染列表的指令是; 只渲染一次的指令是。
(4) 自定义指令分为注册、注册两种方式。全局注册使用来定义。
3. 简答题
(1) 简述vif与vshow指令在使用上的区别。
(2) 事件处理的修饰符有哪些?分别代表什么意思?
(3) 自定义指令钩子函数有哪些?
项目实战3
1. 内置指令实战——课程模块维护
扫一扫
视频讲解
【实战要求】
(1) 学会引入vue.global.js文件,完成简易表单设计。
(2) 学会定义Vue组件对象,会配置data和methods等选项。
(3) 学会使用von、vmodel及vfor等内置指令。
(4) 学会使用数组相关方法,完成课程增加与删除操作。
【设计要求】
按如图329所示的页面效果,完成项目实战。具体设计要求如下。
图329课程管理页面
(1) 设计表单。表单中有3个文本输入框,分别输入课程代号、课程名称和课程学分,分别使用vmodel指令绑定id、name和credit属性。另外,还有一个普通按钮和一个清空按钮,value值分别为“增选课程”“清空”,绑定单击事件,分别调用addCourse()和clear()方法。
(2) 课程模块清单显示。课程属性包含课程代号(id)、课程名称(name)和课程学分(credit)。在
元素上采用vfor指令遍历所有课程信息。课程信息保存在courses对象数组中,并初始设置4门课程信息,如图329所示。每门课程后面添加一个“删除”普通按钮,单击此按钮,调用deleteCourse(i)方法,将从课程对象数组中删除此门课程。
(3) 定义相关方法。在methods选项中定义addCourse()、deleteCourse(i)和clear()方法。其中,addCourse()方法的功能是将添加课程信息(不能为空)从数组的开头处插入课程对象数组中; deleteCourse(i)方法的功能是删除i位置上指定的元素; clear()方法的功能是清除3个文本输入框中的内容。
【实战步骤】
(1) 建立HTML文件。将项目文件命名为vueex31.html,在
标记中引入vue.global.js文件,按设计要求(1)完成“课程模块维护”表单内容的设计。
(2) 定义Vue组件。分别完成data、methods等选项的配置。
定义data(){return{}}。分别定义id、name、credit等变量,按设计要求(2)完成courses对象数组的初始化工作。
配置methods选项。定义addCourse()、deleteCourse(i)和clear()等3个方法。方法定义的形式如下。
functionName(){…}
functionName:function(){…}
(3) 项目调试并运行。在浏览器中调试页面,输入课程代号、课程名称和课程学分后,单击“增选课程”按钮,查看课程信息是否添加在所有课程信息的最前面,如果是,则程序设计正确。再单击“清空”按钮,查看3个文本输入框中的内容是否清空。如果有错,可根据错误信息进行修改。单击课程信息后面的“删除”按钮,查看是否可以正确删除该门课程。
扫一扫
视频讲解
2. 自定义指令实战——自定义vimg指令
【实战要求】
(1) 学会引入vue.global.js文件,完成HTML文档基本结构的定义。
(2) 学会定义Vue组件对象,并配置data和directives等选项。
(3) 学会全局注册自定义指令vimg。使用箭头函数定义指令相关参数(el、binding)。
(4) 学会使用el.style对象的相关DOM属性,完成图像加载等样式设置。
【设计要求】
按如图330所示的页面效果,完成项目实战。具体设计要求如下。
图330自定义vimg指令
(1) 在中插入一个
标记,作为视图展示区,其id为app,
标记内包含一个域标记