Vue 模板语法

  |   0 评论   |   0 浏览

Vue 使用了基于 HTML 的模板语法,将 Vue 实例中的数据和 DOM 绑定在一起。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
使用模板语法可以将程序员从繁琐的 DOM 操作中解放出来。

在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。

Vue 的模板语法可分为两种:

  • 双大括号语法 -- 用来向 HTML 中插入普通文本。
  • 指令 -- 用来绑定 HTML 中的属性和事件,插入 HTML 代码。

双大括号语法

"Mustache" 语法 (双大括号)是最常用的一种形式。

插入文本

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="app">
11        <!-- 文本 -->
12        <span>Message: {{ msg }}</span><br />
13
14        <!-- 使用 v-once 指令,一次性插值 -->
15        <span v-once>这个将不会改变: {{ msg }}</span>
16    </div>
17
18</body>
19<script>
20    var app = new Vue({
21        el: '#app',
22        data: {
23            msg: 'Hello Vue!'
24        }
25    })
26</script>
27
28</html>

使用 JavaScript 表达式

除了可以直接插入文本,在模板中还可以使用 JavaScript 表达式。并且,每个绑定只能包含单个表达式

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="app">
11        <p>{{ num + 1 }}</p>
12
13        <p>{{ ok ? 'YES' : 'NO' }}</p>
14
15        <p>{{ message.split('').reverse().join('') }}</p>
16
17        <p v-bind:id="'list-' + id"></p>
18
19    </div>
20
21</body>
22<script>
23    var app = new Vue({
24        el: '#app',
25        data: {
26            num: 1,
27            ok: true,
28            message: 'hello',
29            id: '007'
30        }
31    })
32</script>
33
34</html>

指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值通常是单个 JavaScript 表达式。

参数

指令后可以接受一个“参数”,这个“参数”可以是 HTML 元素的属性,例如:

1<!-- `href` 是HTML属性,url 是Vue实例中定义的变量,`v-bind` 将两者绑定在一起-->
2<a v-bind:href="url"> ... </a>

这个“参数”也可以是DOM事件的名称,例如:

1<!-- `click` 是点击事件,`doSomething` 是Vue实例中定义的事件处理函数,`v-bind` 将两者绑定在一起-->
2<a v-on:click="doSomething"> ... </a>

动态参数

也可以在指令参数中使用 JavaScript 表达式,方法是用方括号括起来:

1<a v-on:[eventName]="doSomething"> ... </a>

修饰符

修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

插入原生 HTML

双大括号中的内容会被解析为普通文本,若要插入 HTML 代码,则需使用 v-html 指令。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="example1" class="demo">
11        <!-- 解析为普通文本 -->
12        <p>Using mustaches: {{ rawHtml }}</p>
13        <!-- 解析为 HTML,这里的 `<span>` 标签会被替换为 rawHtml 的值 -->
14        <p>Using v-html directive: <span v-html="rawHtml"></span></p>
15    </div>
16    <script>
17        new Vue({
18            el: '#example1',
19            data: function () {
20                return {
21                    rawHtml: '<span style="color: red">This should be red.</span>'
22                }
23            }
24        })
25    </script>
26
27</body>
28<style>
29    .demo {
30        font-family: sans-serif;
31        border: 1px solid #eee;
32        border-radius: 2px;
33        padding: 20px 30px;
34        margin-top: 1em;
35        margin-bottom: 40px;
36        user-select: none;
37        overflow-x: auto;
38    }
39</style>
40
41</html>

在站点动态渲染 HTML 容易导致 XSS 攻击,要谨慎使用。

绑定 Attribute

通过 v-bind 指令可以将 Vue 数据与 HTML 元素属性绑定起来。

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="app">
11        <!-- 绑定 id 值 -->
12        <div v-bind:id="dynamicId"></div>
13
14        <!-- 绑定 disabled 值 -->
15        <button v-bind:disabled="isButtonDisabled">Button</button>
16    </div>
17
18</body>
19<script>
20    var app = new Vue({
21        el: '#app',
22        data: {
23            id: '007',
24            isButtonDisabled: false
25        }
26    })
27</script>
28
29</html>

条件渲染

v-if

v-if 指令用于条件性地渲染一块内容。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="app">
11        <!-- 单独使用 v-if -->
12        <h1 v-if="awesome">Vue is awesome!</h1>
13
14        <!-- v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。 -->
15        <div v-if="Math.random() > 0.5">
16            Now you see me
17        </div>
18        <div v-else>
19            Now you don't
20        </div>
21
22        <!-- v-else-if 可以连续使用(2.1.0 新增) -->
23        <div v-if="type === 'A'">
24            A
25        </div>
26        <div v-else-if="type === 'B'">
27            B
28        </div>
29        <div v-else-if="type === 'C'">
30            C
31        </div>
32        <div v-else>
33            Not A/B/C
34        </div>
35
36    </div>
37
38
39</body>
40<script>
41    var app = new Vue({
42        el: '#app',
43        data: {
44            awesome: true,
45            type: 'C'
46        }
47    })
48</script>
49
50</html>

v-show

用来根据条件展示元素,示例:

1<h1 v-show="ok">Hello!</h1>

v-if 不同的是,带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。v-show 不支持 <template> 元素,也不支持 v-else

v-ifv-show

v-ifv-show 的区别:

  • v-if 是真正的条件渲染,在切换过程中可能会有子组件和监听器的销毁和重建。它是惰性的,只有条件第一次变为真时,才会开始渲染条件块。
  • v-show 只是简单基于 CSS 进行切换,不管初始条件是什么,元素总是被渲染。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

列表渲染

v-for 中使用数组

可以用 v-for 指令基于一个数组来渲染一个列表。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <ul id="example-1">
11        <li v-for="item in items" :key="item.message">
12            {{ item.message }}
13        </li>
14    </ul>
15</body>
16<script>
17    var example1 = new Vue({
18        el: '#example-1',
19        data: {
20            items: [
21                { message: 'Foo' },
22                { message: 'Bar' }
23            ]
24        }
25    })
26</script>
27
28</html>

v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <ul id="example-2">
11        <!-- 索引参数名为 index,索引值从 0 开始 -->
12        <li v-for="(item, index) in items">
13            {{ parentMessage }} - {{ index }} - {{ item.message }}
14        </li>
15    </ul>
16</body>
17<script>
18    var example2 = new Vue({
19        el: '#example-2',
20        data: {
21            parentMessage: 'Parent',
22            items: [
23                { message: 'Foo' },
24                { message: 'Bar' }
25            ]
26        }
27    })
28</script>
29
30</html>

另外,可以用 of 替换 in 作为分隔符:

1<div v-for="item of items"></div>

v-for 中使用对象

也可以使用 v-for 来遍历一个对象的属性。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="v-for-object">
11        <ul class="demo">
12            <li v-for="value in object">
13                {{ value }}
14            </li>
15        </ul>
16
17        <p>可以使用第二个参数:对象属性名 name</p>
18        <ul class="demo">
19            <li v-for="(value, name) in object">
20                {{ name }}: {{ value }}
21            </li>
22        </ul>
23
24        <p>也可以使用第三个参数:索引 index</p>
25        <ul class="demo">
26            <li v-for="(value, name, index) in object">
27                {{ index }}. {{ name }}: {{ value }}
28            </li>
29        </ul>
30    </div>
31
32</body>
33<script>
34    new Vue({
35        el: '#v-for-object',
36        data: {
37            object: {
38                title: 'How to do lists in Vue',
39                author: 'Jane Doe',
40                publishedAt: '2016-04-10'
41            }
42        }
43    })
44</script>
45
46</html>

v-for 中使用数值

v-for 也可以接受整数,生成一个从 1 开始的数值序列。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="demo">
11        <span v-for="n in 10"> {{ n }} </span>
12    </div>
13</body>
14
15<script>
16    var demo = new Vue({
17        el: "#demo"
18    })
19</script>
20
21</html>

事件处理

监听事件

使用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="example-1">
11        <button v-on:click="counter += 1">Add 1</button>
12        <p>The button above has been clicked {{ counter }} times.</p>
13    </div>
14</body>
15
16<script>
17    var example1 = new Vue({
18        el: '#example-1',
19        data: {
20            counter: 0
21        }
22    })
23</script>
24
25</html>

事件处理方法

v-on 可以接收一个需要调用的方法名称。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="example-2">
11        <!-- `greet` 是在下面定义的方法名 -->
12        <button v-on:click="greet">Greet</button>
13    </div>
14</body>
15
16<script>
17    var example2 = new Vue({
18        el: '#example-2',
19        data: {
20            name: 'Vue.js'
21        },
22        // 在 `methods` 对象中定义方法
23        methods: {
24            greet: function (event) {
25                // `this` 在方法里指向当前 Vue 实例
26                alert('Hello ' + this.name + '!')
27                // `event` 是原生 DOM 事件
28                if (event) {
29                    alert(event.target.tagName)
30                }
31            }
32        }
33    })
34</script>
35
36</html>

调用处理方法

除了直接绑定处理方法名称,还可以调用事件处理方法,给方法传入参数。

示例

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="example-3">
11        <button v-on:click="say('hi')">Say hi</button>
12        <button v-on:click="say('what')">Say what</button>
13    </div>
14</body>
15
16<script>
17    new Vue({
18        el: '#example-3',
19        methods: {
20            say: function (message) {
21                alert(message)
22            }
23        }
24    })
25</script>
26
27</html>

Vue 提供了特殊变量 $event ,用来访问原始的 DOM 事件。

 1<!DOCTYPE html>
 2<html>
 3
 4<head>
 5    <title>Template Syntax</title>
 6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
 7</head>
 8
 9<body>
10    <div id="example-3">
11        <button v-on:click="warn('Form cannot be submitted yet.', $event)">
12            Submit
13        </button>
14    </div>
15</body>
16
17<script>
18    new Vue({
19        el: '#example-3',
20        methods: {
21            warn: function (message, event) {
22                // 现在我们可以访问原生事件对象
23                if (event) {
24                    event.preventDefault()
25                    alert(event)
26                }
27                alert(message)
28            }
29        }
30    })
31</script>
32
33</html>

表单输入绑定

使用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • texttextarea 元素使用 value property 和 input 事件。
  • checkboxradio 使用 checked property 和 change 事件。
  • select 字段将 value 作为 prop 并将 change 作为事件。

例如

1<input v-model="searchText">

等价于

1<input v-bind:value="searchText" v-on:input="searchText = $event.target.value">

其中,$$event.target.value 是当前元素的 value 属性值,事件触发时将 value 的值赋给 searchText。而当 searchText 发生变动时,同样会赋值给元素的 value 属性。

基础用法

示例

  1<!DOCTYPE html>
  2<html>
  3
  4<head>
  5    <title>Template Syntax</title>
  6    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  7</head>
  8
  9<body>
 10
 11    <div id="example-1">
 12        <h3>文本</h3>
 13        <input v-model="message1" placeholder="edit me">
 14        <p>Message is: {{ message1 }}</p>
 15
 16        <br>
 17        <h3>多行文本</h3>
 18        <span>Multiline message is:</span>
 19        <p style="white-space: pre-line;">{{ message2 }}</p>
 20        <br>
 21        <textarea v-model="message2" placeholder="add multiple lines"></textarea>
 22
 23        <br>
 24        <h3>复选框</h3>
 25        <p>单个复选框,绑定到布尔值:</p>
 26        <input type="checkbox" id="checkbox" v-model="checked">
 27        <label for="checkbox">{{ checked }}</label>
 28        <br>
 29        <p>多个复选框,绑定到同一个数组:</p>
 30        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
 31        <label for="jack">Jack</label>
 32        <input type="checkbox" id="john" value="John" v-model="checkedNames">
 33        <label for="john">John</label>
 34        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
 35        <label for="mike">Mike</label>
 36        <br>
 37        <span>Checked names: {{ checkedNames }}</span>
 38
 39        <br>
 40        <h3>单选按钮</h3>
 41        <input type="radio" id="one" value="One" v-model="picked">
 42        <label for="one">One</label>
 43        <br>
 44        <input type="radio" id="two" value="Two" v-model="picked">
 45        <label for="two">Two</label>
 46        <br>
 47        <span>Picked: {{ picked }}</span>
 48
 49        <br>
 50        <h3>下拉列表</h3>
 51        <p>单选:</p>
 52        <select v-model="selected">
 53            <option disabled value="">请选择</option>
 54            <option>A</option>
 55            <option>B</option>
 56            <option>C</option>
 57        </select>
 58        <span>Selected: {{ selected }}</span>
 59
 60        <br>
 61        <p>多选(绑定到数组):</p>
 62        <select v-model="selected2" multiple style="width: 50px;">
 63            <option>A</option>
 64            <option>B</option>
 65            <option>C</option>
 66        </select>
 67        <br>
 68        <span>Selected: {{ selected2 }}</span>
 69
 70        <br>
 71        <p>用 v-for 渲染的动态选项:</p>
 72        <select v-model="selected3">
 73            <option v-for="option in options" v-bind:value="option.value">
 74                {{ option.text }}
 75            </option>
 76        </select>
 77        <span>Selected: {{ selected3 }}</span>
 78    </div>
 79
 80</body>
 81
 82<script>
 83    new Vue({
 84        el: '#example-1',
 85        data: {
 86            message1: '',
 87            message2: '',
 88            checked: false,
 89            checkedNames: [],
 90            picked: '',
 91            selected: '',
 92            selected2: [],
 93            selected3: 'A',
 94            options: [
 95                { text: 'One', value: 'A' },
 96                { text: 'Two', value: 'B' },
 97                { text: 'Three', value: 'C' }
 98            ]
 99        }
100    })
101</script>
102
103</html>

值绑定

当需要将值表单元素中的值绑定到 Vue 实例的动态 property 上时,可以使用 v-bind 实现。

单选按钮

1<input type="radio" v-model="pick" v-bind:value="a">
1// 当选中时
2vm.pick === vm.a

下拉列表选项

1<select v-model="selected">
2    <!-- 内联对象字面量 -->
3  <option v-bind:value="{ number: 123 }">123</option>
4</select>
1// 当选中时
2typeof vm.selected // => 'object'
3vm.selected.number // => 123

复选框

1<input
2  type="checkbox"
3  v-model="toggle"
4  true-value="yes"
5  false-value="no"
6>
1// 当选中时
2vm.toggle === 'yes'
3// 当没有选中时
4vm.toggle === 'no'

修饰符

.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:

1<!-- 在“change”时而非“input”时更新 -->
2<input v-model.lazy="msg">

.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

1<input v-model.number="age" type="number">

.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

1<input v-model.trim="msg">

指令缩写

当频繁的使用以 v- 作为前缀的指令时,会感到比较繁琐。因此,Vue 为 v-bindv-on 这两个最常用的指令,提供了缩写形式。

v-bind 缩写

1<!-- 完整语法 -->
2<a v-bind:href="url"> ... </a>
3
4<!-- 缩写 -->
5<a :href="url"> ... </a>
6
7<!-- 动态参数的缩写 -->
8<a :[key]="url"> ... </a>

v-on 缩写

1<!-- 完整语法 -->
2<a v-on:click="doSomething"> ... </a>
3
4<!-- 缩写 -->
5<a @click="doSomething"> ... </a>
6
7<!-- 动态参数的缩写 (2.6.0+) -->
8<a @[event]="doSomething"> ... </a>