跳至主要內容

模板语法

Sankgao约 2380 字大约 8 分钟FrontendVue3

Vue 使用一种基于 HTML 的模板语法,能够 声明式 地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。

在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。

如果您对虚拟 DOM 的概念比较熟悉,并且偏好直接使用 JavaScript,您也可以结合可选的 JSX 支持 直接手写渲染函数 而不采用模板。但请注意,这将不会享受到和模板同等级别的编译时优化。

文本插值

最基本的数据绑定形式是文本插值,它使用的是 “Mustache” 语法(即双大括号):

<span>Message: {{ msg }}</span>

双大括号标签会被替换为 相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。

原始 HTML

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,您需要使用 v-html 指令:

<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

Using text interpolation: <span style="color: red">This should be red.</span>

Using v-html directive: This should be red.

这里看到的 v-html 属性被称为一个 指令。指令由 v- 作为前缀,表明它们是一些由 Vue 提供的特殊属性,它们将为渲染的 DOM 应用特殊的响应式行为。这里做的事情简单来说就是:在当前组件实例上,将此元素的 innerHTML 与 rawHtml 属性保持同步。

span 的内容将会被替换为 rawHtml 属性的值,插值为纯 HTML——数据绑定将会被忽略。注意,您不能使用 v-html 来拼接组合模板,因为 Vue 不是一个基于字符串的模板引擎。在使用 Vue 时,应当使用组件作为 UI 重用和组合的基本单元。

安全警告

在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞open in new window。请仅在内容安全可信时再使用 v-html,并且 永远不要 使用用户提供的 HTML 内容

Attribute 绑定

双大括号不能在 HTML 属性中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令:

<div v-bind:id="dynamicId"></div>

v-bind 指令指示 Vue 将元素的 id attribute 与组件的 dynamicId 属性保持一致。如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

简写

因为 v-bind 非常常用,特意提供了一个特定的简写语法:

<div :id="dynamicId"></div>

开头为 : 的 attribute 可能和一般的 HTML attribute 看起来不太一样,但它的确是合法的 attribute 名称字符,并且所有支持 Vue 的浏览器都能正确解析它。此外,他们不会出现在最终渲染的 DOM 中。简写语法是可选的。

布尔型 Attribute

布尔型 attributeopen in new window 依据 true/false 值来决定 attribute 是否应该存在于该元素上。disabledopen in new window 就是最常见的例子之一。

v-bind 在这种场景下的行为略有不同:

<button :disabled="isButtonDisabled">Button</button>

isButtonDisabled真值open in new window 或一个空字符串(即 <button disabled="">)时,元素会包含这个 disabled attribute。而当其为其他 假值open in new window 时 attribute 将被忽略。

动态绑定多个值

如果您有像这样的一个包含多个 attribute 的 JavaScript 对象:

const objectOfAttrs = {
  id: 'container',
  class: 'wrapper'
}

通过不带参数的 v-bind,您可以将它们绑定到单个元素上:

<div v-bind="objectOfAttrs"></div>

使用 JavaScript 表达式

至此仅在模板中绑定了一些简单的属性名。但是 Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式:

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>

这些表达式都会被作为 JavaScript ,以当前组件实例为作用域解析执行。

在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上:

  • 在文本插值中(双大括号)
  • 在任何 Vue 指令(以 v- 开头的特殊 attribute)attribute 的值中

仅支持表达式

每个绑定仅支持 单一表达式,也就是一段能够被求值的 JavaScript 代码。一个简单的判断方法是是否可以合法地写在 return 后面。

因此,下面的例子都是 无效 的:

<!-- 这是一个语句,而非表达式 -->
{{ var a = 1 }}

<!-- 条件控制也不支持,请使用三元表达式 -->
{{ if (ok) { return message } }}

调用函数

可以在绑定的表达式中使用一个组件暴露的方法:

<span :title="toTitleDate(date)">
  {{ formatDate(date) }}
</span>

提示

绑定在表达式中的方法在组件每次更新时都会被重新调用,因此 应该产生任何副作用。比如:改变数据或触发异步操作

受限的全局访问

模板中的表达式将被沙盒化,仅能够访问到 有限的全局对象列表open in new window。该列表中会暴露常用的内置全局对象。比如:MathDate

没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如:用户附加在 window 上的属性。然而,您也可以自行在 app.config.globalProperties 上显式地添加它们,供所有的 Vue 表达式使用。

指令 Directives

指令是带有 v- 前缀的特殊 attribute。Vue 提供了许多 内置指令,包括上面所介绍的 v-bindv-html

指令 attribute 的期望值为一个 JavaScript 表达式(除了少数几个例外,即之后要讨论到的 v-forv-onv-slot)。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。以 v-if 为例:

<p v-if="seen">Now you see me</p>

这里,v-if 指令会基于表达式 seen 的值的真假来移除/插入该 <p> 元素。

参数 Arguments

某些指令会需要一个 “参数”,在指令名后通过一个冒号隔开做标识。例如:用 v-bind 指令来响应式地更新一个 HTML attribute:

<a v-bind:href="url"> ... </a>

<!-- 简写 -->
<a :href="url"> ... </a>

这里 href 就是一个参数,它告诉 v-bind 指令将表达式 url 的值绑定到元素的 href attribute 上。在简写中,参数前的一切(例如 v-bind:)都会被缩略为一个 : 字符。

另一个例子是 v-on 指令,它将监听 DOM 事件:

<a v-on:click="doSomething"> ... </a>

<!-- 简写 -->
<a @click="doSomething"> ... </a>

这里的参数是要监听的事件名称:clickv-on 有一个相应的缩写,即 @ 字符。

动态参数

同样在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:

<!--
注意,参数表达式有一些约束,
参见下面 “动态参数值的限制” 与 “动态参数语法的限制” 的解释
-->
<a v-bind:[attributeName]="url"> ... </a>

<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

这里的 attributeName 会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。例如:如果您的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href

相似地,您还可以将一个函数绑定到动态的事件名称上:

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

<!-- 简写 -->
<a @[eventName]="doSomething">

在此示例中,当 eventName 的值是 "focus" 时,v-on:[eventName] 就等价于 v-on:focus

动态参数值的限制

动态参数中表达式的值应当是一个字符串,或者是 null。特殊值 null 意为显式移除该绑定。其他非字符串的值会触发警告。

动态参数语法的限制

动态参数表达式因为某些字符的缘故有一些语法限制,比如:空格和引号,在 HTML attribute 名称中都是不合法的。例如下面的示例:

<!-- 这会触发一个编译器警告 -->
<a :['foo' + bar]="value"> ... </a>

如果您需要传入一个复杂的动态参数,推荐使用 计算属性 替换复杂的表达式,也是 Vue 最基础的概念之一。

当使用 DOM 内嵌模板(直接写在 HTML 文件里的模板)时,需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写:

<a :[someAttr]="value"> ... </a>

上面的例子将会在 DOM 内嵌模板中被转换为 :[someattr]。如果您的组件拥有 someAttr 属性而非 someattr,这段代码将不会工作。单文件组件内的模板 受此限制。

修饰符 Modifiers

修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如:.prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault()

<form @submit.prevent="onSubmit">...</form>

最后,在这里您可以直观地看到完整的指令语法:

指令语法图
指令语法图