模板语法
Vue 使用一种基于 HTML 的模板语法,允许你声明式地将组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。
文本插值
数据绑定最常见的形式就是使用 "Mustache" 语法(双大括号)的文本插值:
<template>
<span>Message: {{ msg }}</span>
</template>
<script>
export default {
data() {
return {
msg: 'Hello Vue!'
}
}
}
</script>
双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html
指令。
一次性插值
通过使用 v-once
指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新:
<template>
<span v-once>这个将不会改变: {{ msg }}</span>
</template>
原始 HTML
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html
指令:
<template>
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
</template>
<script>
export default {
data() {
return {
rawHtml: '<span style="color: red">This should be red.</span>'
}
}
}
</script>
安全警告
在你的站点上动态渲染任意的 HTML 是非常危险的,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
Attribute 绑定
双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind
指令:
<template>
<div v-bind:id="dynamicId"></div>
<!-- 简写 -->
<div :id="dynamicId"></div>
</template>
<script>
export default {
data() {
return {
dynamicId: 'my-id'
}
}
}
</script>
布尔型 Attribute
布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。
<template>
<button :disabled="isButtonDisabled">Button</button>
</template>
<script>
export default {
data() {
return {
isButtonDisabled: true
}
}
}
</script>
动态绑定多个值
如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:
data() {
return {
objectOfAttrs: {
id: 'container',
class: 'wrapper'
}
}
}
通过不带参数的 v-bind
,你可以将它们绑定到单个元素上:
<template>
<div v-bind="objectOfAttrs"></div>
</template>
使用 JavaScript 表达式
到目前为止,在我们的模板中,我们只绑定简单的 property 键值。但实际上,对于所有的数据绑定,Vue 都提供了完全的 JavaScript 表达式支持。
<template>
<div>
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="'list-' + id"></div>
</div>
</template>
<script>
export default {
data() {
return {
number: 1,
ok: true,
message: 'Hello',
id: 'main'
}
}
}
</script>
这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。
仅支持表达式
每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流程控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
调用函数
可以在绑定的表达式中调用一个组件暴露的方法:
<template>
<span :title="toTitleDate(date)">
{{ formatDate(date) }}
</span>
</template>
<script>
export default {
data() {
return {
date: new Date()
}
},
methods: {
formatDate(date) {
return date.toLocaleDateString()
},
toTitleDate(date) {
return date.toLocaleString()
}
}
}
</script>
指令
指令是带有 v-
前缀的特殊 attribute。Vue 提供了许多内置指令,包括上面我们所介绍的 v-bind
和 v-html
。
指令 attribute 的期望值为一个 JavaScript 表达式(除了少数几个例外,即之后要讨论到的 v-for
、v-on
和 v-slot
)。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。
<template>
<p v-if="seen">现在你看到我了</p>
</template>
<script>
export default {
data() {
return {
seen: true
}
}
}
</script>
参数
某些指令会需要一个"参数",在指令名后通过一个冒号隔开做标识。例如,v-bind
指令被用来响应式地更新 HTML attribute:
<template>
<a v-bind:href="url">链接</a>
<!-- 简写 -->
<a :href="url">链接</a>
</template>
这里 href
就是一个参数,它告诉 v-bind
指令将表达式 url
的值绑定到元素的 href
attribute 上。
另一个例子是 v-on
指令,它将监听 DOM 事件:
<template>
<a v-on:click="doSomething">点击我</a>
<!-- 简写 -->
<a @click="doSomething">点击我</a>
</template>
这里的参数是要监听的事件的名称。
动态参数
同样在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:
<template>
<a v-bind:[attributeName]="url">动态属性</a>
<a v-on:[eventName]="doSomething">动态事件</a>
</template>
<script>
export default {
data() {
return {
attributeName: 'href',
eventName: 'click',
url: 'https://vuejs.org'
}
},
methods: {
doSomething() {
alert('Hello!')
}
}
}
</script>
动态参数值的限制
动态参数期望结果为一个字符串,或者是 null
。特殊值 null
意为显式移除该绑定。其他非字符串的值会触发警告。
动态参数语法的限制
动态参数表达式因为某些字符的缘故有一些语法限制,比如空格和引号,在 HTML attribute 名称中都是不合法的。例如下面的示例:
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value">...</a>
如果你需要传入一个复杂的动态参数,我们推荐使用计算属性替换复杂的表达式。
修饰符
修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如 .prevent
修饰符会告知 v-on
指令对触发的事件调用 event.preventDefault()
:
<template>
<form @submit.prevent="onSubmit">...</form>
</template>
常用指令示例
v-if / v-else / v-else-if
条件渲染:
<template>
<div>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
</template>
<script>
export default {
data() {
return {
awesome: true,
type: 'A'
}
}
}
</script>
v-show
另一个用于条件性展示元素的选项是 v-show
指令:
<template>
<h1 v-show="ok">Hello!</h1>
</template>
<script>
export default {
data() {
return {
ok: true
}
}
}
</script>
不同之处在于 v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为 display
的 CSS 属性。
v-for
列表渲染:
<template>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.message }}
</li>
</ul>
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index }} - {{ item.message }}
</li>
</ul>
<ul>
<li v-for="(value, name) in object" :key="name">
{{ name }}: {{ value }}
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, message: 'Foo' },
{ id: 2, message: 'Bar' }
],
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}
</script>
v-on
事件监听:
<template>
<div>
<button v-on:click="counter += 1">Add 1</button>
<button @click="greet">Greet</button>
<button @click="say('hi')">Say hi</button>
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
</div>
</template>
<script>
export default {
data() {
return {
counter: 0,
name: 'Vue.js'
}
},
methods: {
greet(event) {
alert('Hello ' + this.name + '!')
if (event) {
alert(event.target.tagName)
}
},
say(message) {
alert(message)
},
warn(message, event) {
if (event) {
event.preventDefault()
}
alert(message)
}
}
}
</script>
v-model
双向数据绑定:
<template>
<div>
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<textarea v-model="message2" placeholder="add multiple lines"></textarea>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
</template>
<script>
export default {
data() {
return {
message: '',
message2: '',
checked: false,
selected: ''
}
}
}
</script>
完整示例
<template>
<div class="demo">
<h1>{{ title }}</h1>
<!-- 文本插值 -->
<p>{{ message }}</p>
<!-- HTML 插值 -->
<div v-html="htmlMessage"></div>
<!-- 属性绑定 -->
<img :src="imageSrc" :alt="imageAlt">
<!-- 条件渲染 -->
<p v-if="showMessage">这是一条消息</p>
<button @click="toggleMessage">切换消息</button>
<!-- 列表渲染 -->
<ul>
<li v-for="item in list" :key="item.id">
{{ item.name }}
</li>
</ul>
<!-- 表单绑定 -->
<input v-model="inputValue" placeholder="输入一些文字">
<p>你输入的是: {{ inputValue }}</p>
<!-- 事件处理 -->
<button @click="handleClick">点击我</button>
<button @click="increment">计数: {{ count }}</button>
</div>
</template>
<script>
export default {
name: 'TemplateSyntaxDemo',
data() {
return {
title: '模板语法演示',
message: 'Hello Vue!',
htmlMessage: '<strong>这是粗体文本</strong>',
imageSrc: 'https://vuejs.org/images/logo.png',
imageAlt: 'Vue.js Logo',
showMessage: true,
inputValue: '',
count: 0,
list: [
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' },
{ id: 3, name: '橙子' }
]
}
},
methods: {
toggleMessage() {
this.showMessage = !this.showMessage
},
handleClick() {
alert('按钮被点击了!')
},
increment() {
this.count++
}
}
}
</script>
<style scoped>
.demo {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
img {
max-width: 100px;
height: auto;
}
button {
margin: 5px;
padding: 8px 16px;
cursor: pointer;
}
input {
padding: 8px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
下一步
现在你已经了解了 Vue 的模板语法基础,让我们继续学习:
模板语法是 Vue 的核心特性之一,掌握它将让你能够高效地构建动态的用户界面!