大纲
Vue 指令介绍
什么是指令
- 指令(Directives)是带有
v-
前缀的特殊特性 - 指令特性的预期值是:单个 JavaScript 表达式
- 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM(视图)。
插值表达式
花括号
- 格式:
{{表达式}}
- 描述:
- 花括号
{{ }}
只能写在 HTML 的标签体内 - 表达式支持 JS 语法,可以调用 JS 内置函数(必须有返回值)
- 表达式必须有返回结果,例如
1 + 1
,没有结果的表达式不允许使用,例如 let a = 1 + 1
是不合法的表达式 - 可以直接指定 Vue 实例中定义的数据或函数
插值闪烁
使用 {{ }}
方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的 {{ }}
内容,页面加载完毕后才会显示正确的数据,该现象称为 插值闪烁
。Chrome 浏览器可以将网速调慢一些(如下图),然后刷新页面,这样就可以重现 插值闪烁
现象。
v-text 和 v-html 指令
为了解决 插值闪烁
的问题,可以使用 v-text
和 v-html
指令来替代 {{ }}
v-text
:将数据输出到标签内部,如果输出的数据有 HTML 代码,会作为普通文本输出v-html
:将数据输出到标签内部,如果输出的数据有 HTML 代码,会被渲染后再输出
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <span v-html="code"></span> <br> <span v-text="code"></span> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { code: "<h1>Hello World</h1>" } }); </script> </body> </html>
|
代码运行效果
上述 HTML 代码运行后的效果如下,即使是网速较低的时候,也不会出现插值闪烁现象;当没有数据时,会显示空白或者默认数据。
v-bind 指令
HTML 标签的属性不能使用花括号 {{ }}
的形式来绑定,但可以使用 v-bind
指令给 HTML 标签的属性绑定值;而且在将 v-bind
指令用于 class
和 style
时,Vue 做了专门的增强。
绑定 class
使用 v-bind
指令绑定 HTML 标签的 class
。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <span v-bind:class="{'active': isActive, 'text-danger': hasError}">Hello World</span> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { isActive: true, hasError: true } }); </script> </body> </html>
|
绑定 style
使用 v-bind
指令绑定 HTML 标签的 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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <span v-bind:style="{'color': fontColor, 'font-size': fontSize}">Hello Vue</span> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { fontColor: 'red', fontSize: '30px' } }); </script> </body> </html>
|
绑定 attribute
使用 v-bind
指令绑定 HTML 标签的 attribute(属性)
。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <a v-bind:href="link">Baidu</a> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { link: 'https://www.baidu.com' } }); </script> </body> </html>
|
绑定其他任意属性
使用 v-bind
指令绑定 HTML 标签的其他任意属性。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <span v-bind:user="userName">Hello World</span> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { userName: 'Jack' } }); </script> </body> </html>
|
v-bind 指令支持缩写
v-bind
指令支持缩写,例如 v-bind:href
可以缩写为 :href
。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <a :href="link">Baidu</a> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { link: 'https://www.baidu.com' } }); </script> </body> </html>
|
v-model 指令
v-model 指令介绍
上述的 v-text
、v-html
、v-bind
可以看做是单向绑定,模型变化会引起视图变化(渲染),但是反过来就不行。而 v-model
指令是双向绑定,模型(Model)与视图(View)之间会互相影响。既然是双向绑定,一定是在视图中可以修改数据,这样就限定了视图的 HTML 标签类型。目前 v-model
的可使用标签有:
radio
:单选框checkbox
:多选框select
:下拉列表input
:单行输入框textarea
:多行文本输入框components
:Vue 中的自定义组件
基本上除了最后一项,其它都是表单的输入项。
v-model 指令使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <label>精通的语言:</label><br> <input type="checkbox" v-model="language" value="java"> Java<br> <input type="checkbox" v-model="language" value="php"> PHP<br> <input type="checkbox" v-model="language" value="c++"> C++<br> <input type="checkbox" v-model="language" value="golang"> Golang<br> <label>选中的语言:</label><br> {{language.join(' , ')}} </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { language: [] } }); </script> </body> </html>
|
- 多个
checkBox
对应一个 Model 时,Model 的类型是一个数组;单个 checkbox
时,Model 的类型是 boolean
select
单选对应的值是字符串类型,多选对应的值是数组类型radio
对应的值是 input
标签的 value
值text
和 textarea
对应值是字符串类型
代码运行效果
使用 v-model
指令,上述 HTML 代码运行后的效果如下:
v-on 指令
v-on 指令介绍
v-on
指令用于给页面标签绑定事件(如点击事件)。
v-on
指令中可以写 JS 片段,也可以指定在 Vue 实例中定义的函数名称,语法为:v-on:事件名="JS 片段或函数名称"
v-on
指令支持缩写,v-on:click='add'
可以缩写为 @click='add'
v-on 指令使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <button v-on:click="number++">点赞</button> <button @click="cancel">取消点赞</button> <h2>有 {{number}} 个人点赞</h2> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: '#app', data: { number: 0 }, methods: { cancel() { if (this.number > 0) { this.number--; } } } }); </script> </body> </html>
|
v-on 指令的事件修饰符
事件修饰符介绍
为了阻止事件冒泡,在事件处理的代码中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管可以在函数中轻松实现这一点,但更好的方式是让函数只拥有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue 为 v-on
指令提供了事件修饰符,而修饰符是由点开头的指令后缀来表示。
.stop
:阻止事件冒泡到父标签.prevent
:阻止默认事件发生.capture
:使用事件捕获模式.self
:只有标签自身触发事件才执行(冒泡或捕获的都不执行).once
:只执行一次
事件修饰符使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <div style="border: 1px solid red; padding: 20px;" v-on:click="hello"> 大的 Div <div style="border: 1px solid blue; padding: 20px;" v-on:click.stop="hello"> 小的 Div<br /> <a href="http://www.baidu.com" v-on:click.prevent.stop="hello">跳转百度</a> </div> </div> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: '#app', data: { number: 0 }, methods: { hello() { console.log("点击了"); } } }); </script>
</body> </html>
|
v-on 指令的按键修饰符
按键修饰符介绍
在监听键盘事件时,往往需要检查常见的键值。Vue 允许为 v-on
指令在监听键盘事件时添加按键修饰符:
1 2
| <input v-on:keyup.13="submit">
|
由于记住所有的 keyCode
比较困难,所以 Vue 为最常用的按键提供了别名:
1 2 3 4 5
| <input v-on:keyup.enter="submit">
<input @keyup.enter="submit">
|
全部的按键别名如下:
.enter
.tab
.delete
(捕获” 删除” 和” 退格” 键).esc
.space
.up
.down
.left
.right
按键修饰符使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head>
<body> <div id="app"> <span>输入数字:</span><input text="text" v-model="number" v-on:keyup.up="number+=2" v-on:keyup.down="number-=2"> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: '#app', data: { number: 0 } }); </script> </body> </html>
|
组合按键的使用
可以用如下修饰符来实现仅在按下相应按键时,才触发鼠标或键盘事件的监听器。
1 2 3 4 5
| <input v-on:keyup.alt.67="clear">
<div v-on:click.ctrl="doSomething">Do something</div>
|
v-for 指令
v-for 指令介绍
通过遍历数据来渲染页面是非常常见的需求,在 Vue 中可以通过 v-for
指令来实现。
v-for 指令使用
遍历数组
语法:v-for="item in items"
items
:要遍历的数组,需要在 Vue 实例的 data
中定义好item
:迭代得到的当前正在遍历的元素
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="user in users"> {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { users: [ { name: '柳岩', gender: '女', age: 23 }, { name: '刘亦菲', gender: '女', age: 28 }, { name: '古力娜扎', gender: '女', age: 26 } ] } }); </script> </body> </html>
|
数组下标
若希望在遍历数组时,获取当前数组元素的下标,可以指定第二个参数。
语法:v-for="(item, index) in items"
items
:要遍历的数组,需要在 Vue 实例的 data
中定义好item
:迭代得到的当前正在遍历的元素index
:迭代到的当前元素的索引,从 0 开始
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="(user, index) in users"> 第 {{index+1}} 个女明星: {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { users: [ { name: '柳岩', gender: '女', age: 23 }, { name: '刘亦菲', gender: '女', age: 28 }, { name: '古力娜扎', gender: '女', age: 26 } ] } }); </script> </body> </html>
|
遍历对象
v-for
指令除了可以迭代数组,还可以迭代对象。语法如下:
v-for="value in object"
,得到的是对象的属性值v-for="(value, key) in object"
,得到的第一个是对象的属性值,第二个是对象的属性名v-for="(value, key, index) in object"
,得到的第一个是对象的属性值,第二个是对象的属性名,第三个是索引(从 0 开始)
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="(value, key, index) in user"> 第 {{index+1}} 个属性: {{key}} - {{value}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { user: { name: '柳岩', gender: '女', age: 23 } } }); </script> </body> </html>
|
遍历优化
遍历数据时,建议都加上 v-bind:key
指令来区分不同的数据(标识每一个元素的唯一特征),这样 Vue 就可以使用” 就地复用” 策略有效地提高渲染效率。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="user in users" v-bind:key="user.id"> {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { users: [ { id: 1, name: '柳岩', gender: '女', age: 23 }, { id: 2, name: '刘亦菲', gender: '女', age: 28 }, { id: 3, name: '古力娜扎', gender: '女', age: 26 } ] } }); </script> </body> </html>
|
若遍历的数据(数组或者对象)没法通过唯一标识来区分时,可以直接使用 index
索引来作为 key
。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="(user, index) in users" v-bind:key="index"> {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { users: [ { name: '柳岩', gender: '女', age: 23 }, { name: '刘亦菲', gender: '女', age: 28 }, { name: '古力娜扎', gender: '女', age: 26 } ] } }); </script> </body> </html>
|
最佳实践
- 如果
items
是普通数组,可以使用 index
作为每个元素的唯一标识 - 如果
items
是对象数组,可以使用 item.id
作为每个元素的唯一标识
v-if 指令
v-if 指令介绍
v-if
指令,用于条件判断。当得到结果为 true
时,所在的标签才会被渲染。
v-if 指令使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <button v-on:click="show = !show">切换显示模式</button> <h1 v-if="show">Hello World</h1> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { show: true } }); </script> </body> </html>
|
与 v-for 结合使用
当 v-if
和 v-for
指令同时使用时,v-for
指令的优先级更高。也就是说,Vue 会先遍历数据,然后再判断条件。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <ul> <li v-for="(user, index) in users" v-if="user.gender == '女'"> 第 {{index+1}} 个明星: {{user.name}} - {{user.gender}} - {{user.age}} </li> </ul> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { users: [ { name: '柳岩', gender: '女', age: 23 }, { name: '刘亦菲', gender: '女', age: 28 }, { name: '刘德华', gender: '男', age: 60 } ] } }); </script> </body> </html>
|
v-show 指令
v-show 指令介绍
v-show
指令,也用于条件判断,当得到结果为 true
时,所在的标签才会被显示。v-show
与 v-if
指令不同的地方在于,当结果为 false
时,v-show
指令是通过添加 CSS 样式 style="display: none"
来隐藏标签内容的。
v-show 指令使用
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <button v-on:click="show = !show">切换显示模式</button> <h1 v-show="show">Hello World</h1> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script> let app = new Vue({ el: "#app", data: { show: true } }); </script> </body> </html>
|
v-else 与 v-else-if 指令
v-else
指令必须紧跟在带 v-if
或者 v-else-if
指令的标签的后面,否则它将不会被识别。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <button v-on:click="random = Math.random()">生成随机数</button> <p></p> <h3>{{random}}</h3>
<h2 v-if="random >= 0.75"> >= 0.75 </h2>
<h2 v-else-if="random >= 0.5"> >= 0.5 </h2>
<h2 v-else-if="random >= 0.2"> >= 0.2 </h2>
<h2 v-else> < 0.2 </h2> </div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<script type="text/javascript"> let app = new Vue({ el: "#app", data: { random: 1 } }) </script> </body> </html>
|