Vue.js模板语法
在之前的章节中其实已经涉及过部分模板语法,例如 @click
、{{msg}}
等,模板语法是逻辑和视图之间沟通的桥梁,使用模板语法编写的 HTML
会响应 Vue
实例中的各种变化。简单来说,Vue
实例中可以随心所欲地将相关内容渲染在页面上,模板语法功不可没。有了模板语法,可以让用户界面渲染的内容和用户交互操作的代码更具有逻辑性。
Vue
模板语法是 Vue
中常用的技术之一,它的具体功能就是让与用户界面渲染和用户交互操作的代码经过一系列的编译,生成 HTML
代码,最终输出到页面上。但是,在底层的实现上,Vue
将模板编译成 DOM
渲染函数。结合响应系统,Vue
能够智能地计算出最少需要重新渲染多少组件,并把 DOM
操作次数减到最少。
Vue.js
使用了基于 HTML
的模板语法,允许以声明方式将 DOM
绑定至底层 Vue
实例的数据。所有 Vue.js
的模板都是合法的 HTML
,因此可以被遵循规范的浏览器和 HTML
解析器所解析。
插值表达式
下面来看一段简单的代码,如示例代码2-2-1所示。
<template>
<div id="app">
{{ message }}
</div>
</template>
上面的实例代码中出现的 {{message}}
在之前的章节中也出现过多次,它的正式名称叫作插值(Mustache)表达式,也叫作插值标签。它是 Vue
模板语法中最重要的,也是最常用的,使用两个大括号 “{{}}
” 来包裹,在渲染时会自动对里面的内容进行解析。Vue
模板中的插值常见的使用方法有:文本、原始HTML、属性、JavaScript 表达式、指令 和 修饰符 等。
文本插值(v-text)
所谓文本插值,就是一对大括号中的数据经过编译和渲染出来是一个普通的字符串文本。同时,message
在这里也形成了一个数据绑定,无论何时,绑定的数据对象上的 message
属性发生了改变,插值处的内容都会实时更新。文本插值表达式的使用如示例代码2-2-2所示。
<div id="app">
{{ message }}
</div>
// 等同于
<div id="app" v-text="message"></div>
<div>
中的内容会被替换成 message
的内容,同时实时更新体现了双向绑定的作用。但是,也可以通过设置 v-once
指令,使得数据改变时,插值处的内容不会更新。不过,注意这会影响该节点上所有的数据绑定。
在 Vue
中给 DOM
元素添加 v-***
形式的属性的写法叫作指令,v-once
指令的运用如示例代码2-2-3所示。
<div id="app" v-once>
这个将不会改变:{{ message }}
</div>
|
原始HTML插值(v-html)
一对大括号会将数据解析为普通文本,而不是 HTML
代码。为了输出真正的 HTML
代码,需要使用 v-html
指令,如示例代码2-2-4所示。
Vue.createApp({
data() {
return {
rawHtml: "<div>html文本<span>abc</span></div>"
}
}
}).mount("#app")
<p>{{ rawHtml }}</p>
<p>v-html: <span v-html="rawHtml"></span></p>
上面的代码中,rawHtml
是一段含有 HTML
代码的字符串,直接使用 {{rawHtml}}
并不会解析 HTML
字符串的内容,而是原模原样地显示在页面上。但是,如果使用 v-html
指令,则会作为一段 HTML
代码插入当前这个 <span>
中。如果 rawHtml
中还含有一些插值表达式或者指令,那么 v-html
会忽略解析属性值中的数据绑定。例如这样设置:
data() {
return {
rawHtml: "<div>html文本<span>{{abc}}</span></div>"
}
}
需要注意的是,网页中动态渲染任意的 HTML
可能非常危险,很容易导致 XSS
攻击,请只对可信的内容使用 v-html
指令,绝不要对用户输入的内容使用这个指令。
属性插值
插值语法不能作用在 HTML
的属性上,遇到这种情况应该使用 v-bind
指令。例如,若想给 HTML
的 style
属性动态绑定数据,使用插值可能有这样的写法,如示例代码2-2-5所示。
data() {
return {
str: "#000000"
}
}
<div id="app" style="color:{{str}}"></div>
这样写的插值是无法生效的,也就是 Vue
无法识别写在 HTML
属性上的插值表达式,那么遇到这种情况,可以采用 v-bind
指令,如示例代码2-2-6所示。
data() {
return {
str: "color:#000000"
}
}
<div id="app" v-bind:style="str"></div>
对于布尔属性(它们只要存在,就意味着值为 true
),v-bind
工作起来略有不同,在这个例子中为:
<button v-bind:disabled="isButtonDisabled">Button</button>
如果 isButtonDisabled
的值是 null
、undefined
或 false
,则 disabled
属性甚至不会出现在渲染出来的 <button>
元素中。
JavaScript 表达式插值
在之前讲解的插值表达式中,基本上都是一直只绑定简单的属性键值,例如直接将 message
的值显示出来。但是实际情况是,对于所有的数据绑定,Vue.js
都提供了完整的 JavaScript 表达式支持,如示例代码2-2-7所示。
// 单目运算
{{ number + 1 }}
// 三目运算
{{ ok ? 'YES' : 'NO' }}
// 字符串处理
{{ message.split('').reverse().join('') }}
// 拼接字符串
<div v-bind:id="'list-' + id"></div>
例如加法运算、三目运算、字符串的拼接以及常用的 split
处理等,这些表达式会在所属 Vue
实例的数据作用域下作为 JavaScript 代码被解析。
指令
传统意义上的指令就是指挥机器工作的指示和命令,Vue
中的指令是指带有 v-
前缀或者说以 v-
开头的、设置在 HTML
节点上的特殊属性。
指令的作用是,当表达式的值改变时,将其产生的连带影响以响应的方式作用在 DOM
上。之前用到的 v-bind
和 v-model
都属于指令,它们都属于 Vue
中的内置指令,与之相对应的叫作自定义指令。下面就讲解一下 Vue
中主要的内置指令。
v-bind
v-bind
指令可以接受参数,在 v-bind
后面加上一个冒号再跟上参数,这个参数一般是 HTML
元素的属性,如示例代码2-2-8所示。
示例代码2-2-8 v-bind 指令
<a v-bind:href="url">...</a>
<img v-bind:src="url" />
使用 v-bind
绑定 HTML
元素的属性之后,这个属性就有了数据绑定的效果,在 Vue
实例的 data
中定义之后,就会直接替换属性的值。
v-bind
还有一个简写的用法就是直接用冒号而省去 v-bind
,代码如下:
<img :src="url" />
使用 v-bind
和 data
结合可以很便捷地实现数据渲染,但是要注意,并不是所有的数据都需要设置到 data
中,当一些组件中的变量与显示无关或者没有相关的数据绑定逻辑时,也无须设置在 data
中,在 methods
中使用局部变量或者其它地方。这样可以减少 Vue
对数据的响应式监听,从而提升性能。
v-bind
可以绑定来自以下几种地方的数据:
-
data 属性
<template> <div> <button v-bind:title="buttonTitle">Hover over me</button> </div> </template> <script> export default { data() { return { buttonTitle: 'This is a button' }; } }; </script>
-
computed 属性
<template> <div> <button v-bind:title="computedTitle">Hover over me</button> </div> </template> <script> export default { data() { return { baseTitle: 'This is a button' }; }, computed: { computedTitle() { return `${this.baseTitle} - Hover for more info`; } } }; </script>
-
methods 中的返回值
<template> <div> <button v-bind:title="getButtonTitle">Hover over me</button> </div> </template> <script> export default { data() { return { baseTitle: 'This is a button' }; }, methods: { getButtonTitle() { return `${this.baseTitle} - Dynamic Title`; } } }; </script>
-
props
<template> <div> <button v-bind:title="titleFromParent">Hover over me</button> </div> </template> <script> export default { props: { titleFromParent: String } }; </script>
v-if、v-else 和 v-else-if
这 3 个指令与编写代码时使用的 if/else
语句是一样的,一般是搭配起来使用,只有 v-if
可以单独使用,v-else
和 v-else-if
必须搭配 v-if
来使用。
这些指令执行的结果是根据表达式的值 “真或假” 来渲染元素。在切换时,元素及其组件与组件上的数据绑定会被销毁并重建,如示例代码2-2-9所示。
<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>
需要再强调一下,如果 v-if
的值是 false
,那么 v-if
所在的 HTML
的 DOM
节点及其子元素都会被直接移除,这些元素上面的事件和数据绑定也会被移除。
v-show
与 v-if
类似,v-show
也用于控制一个元素是否显示,但是与 v-if
不同的是,如果 v-if
的值是 false
,则这个元素会被销毁,不在 DOM
中。但是,v-show
的元素会始终被渲染并保存在 DOM
中,它只是被隐藏,显示和隐藏只是简单地切换 CSS
的 display
属性,如示例代码2-2-10所示。
<div v-show="type === 'A'">
A
</div>
在 Vue
中,并没有 v-hide
指令,可以用 v-show="!xxx"
来代替。
一般来说,v-if
切换开销更高,而 v-show
的初始渲染开销更高。因此,如果需要非常频繁地切换,使用 v-show
更好;如果在运行时条件很少改变,则使用 v-if
更好。
v-for
与代码中的 for
循环功能类似,可以用 v-for
指令通过一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名,如示例代码2-2-11所示。
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
Vue.createApp({
data() {
return {
items: [
{ message: "Jack" },
{ message: "Tom" }
]
}
}
}).mount("#app")
渲染结果如图2-3所示。

也可以用 of
替代 in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
在使用 v-for
指令时,如果我们在 data
中定义的数组动态地改变,那么执行 v-for
所渲染的结果也会改变,这也是 Vue
中响应式的体现,例如我们对数组进行 push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
操作时,渲染结果也会动态地改变,如示例代码2-2-11所示。
<div id="app">
<button @click="add">add</button>
<ul>
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
</div>
Vue.createApp({
data() {
return {
items: [
{ message: "Jack" },
{ message: "Tom" }
]
}
},
methods:{
add(){
this.items.push({message: "Amy"})
}
}
}).mount("#app")
在 v-for
代码区块中,可以访问当前 Vue
实例的所有其他属性,也就是其他设置在 data
中的值。v-for
还支持一个可选的第二个参数,即当前项的索引,如示例代码2-2-12所示。
<ul id="app">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
Vue.createApp({
data() {
return {
parentMessage: "Parent",
items: [
{ message: "Jack" },
{ message: "Tom" }
]
}
}
}).mount("#app")
渲染结果如图2-4所示。

v-for
指令不仅可以遍历一个数组,还可以遍历一个对象,功能就像 JavaScript 中的 for/in
和 Object.keys()
一样,如示例代码2-2-13所示。
<ul id="app">
<li v-for="value in object">
{{ value }}
</li>
</ul>
Vue.createApp({
data() {
return {
object: {
title: "Big Big",
author: "Jack",
time: "2019-04-10"
}
}
}
}).mount("#app")
渲染结果如图2-5所示。

和使用索引一样,v-for
指令提供的第二个参数为 property
名称(也就是键名),第三个参数为 index
索引,如示例代码2-2-14所示。
<ul id="app">
<li v-for="(value,name,index) in object">
{{ index }}:{{ name }} {{ value }}
</li>
</ul>
Vue.createApp({
data() {
return {
object: {
title: "Big Big",
author: "Jack",
time: "2019-04-10"
}
}
}
}).mount("#app")
渲染结果如图2-6所示。

在使用 Object.keys()
遍历对象时,有时遍历出来的键(Key)的顺序并不是我们定义时的顺序,比如定义时 title
在第一个,author
在第二个,time
在第三个,但是遍历出来却不是这个顺序(这里只是举一个例子,上面代码的应用场景是按照顺序来的)。
需要注意的是,在使用 v-for
遍历对象时,是按照调用 Object.keys()
的结果顺序遍历的,所以在某些情况下并不会按照定义对象的顺序来遍历。若想严格控制顺序,则要在定义时转换成数组来遍历。
为了让 Vue
可以跟踪每个节点,则需要为每项提供一个唯一的 key
属性。如示例代码2-2-15所示。
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
当 Vue
更新使用了 v-for
渲染的元素列表时,它会默认使用 “就地更新” 的策略。如果数据项的顺序被改变了,Vue
将不会移动 DOM
元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染到用户界面上。
Vue
会尽可能地对组件进行高度复用,所以增加 key
可以标识组件的唯一性,目的是为了更好地区别各个组件,key
更深层的意义是为了高效地更新虚拟 DOM
。关于虚拟 DOM
的概念,可以简单理解成 Vue
在每次把数据更新到用户界面时,都会在内部事先定义好前后两个虚拟的 DOM
,一般是对象的形式。通过对比前后两个虚拟 DOM
的异同来针对性地更新部分用户界面,而不是整体更新(没有改变的用户界面部分不去修改,这样可以减少 DOM
操作,提升性能)。设置 key
值有利于 Vue
更高效地查找需要更新的用户界面。不要使用对象或数组之类的非基本类型值作为 v-for
的 key
,请用字符串或数字类型的值。
v-for
指令和 v-if
指令本身是不推荐使用在同一个元素上的,代码如下:
<li v-for="todo in todos" v-if="!todo.isComplete" :key="todo.name">
{{ todo.name }}
</li>
我们在日常开发时,在列表渲染时经常会遇到这种场景,以前在 Vue 2
版本中采用上面的写法并不会报错,然而在 Vue 3
中这样写会报错,如图2-7所示。

因为它们处于同一节点,v-if 的优先级比 v-for 更高,这意味着 v-if
将没有权限访问 v-for
中的变量 todo
,可以将 v-for
指令写在一个空的元素 <template>
上来达到循环效果,同时将 v-if
指令写在 <li>
上来达到是否渲染的效果,这样就不会报错了,代码如下:
<template v-for="todo in todos" :key="todo.name">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
v-on
在之前的章节中也使用过 v-on
指令,这个指令主要用来给 HTML
元素绑定事件,是 Vue
中用得最多的指令之一。v-on
的冒号后面可以跟一个参数,这个参数就是触发事件的名称,v-on
的值可以是一个方法的名字或一个内联语句。和 v-bind
一样,v-on
指令可以省略 v-on:
,而用 @
来代替,如示例代码2-2-16所示。
<div id="app">
<button @click="clickCallback">点我</button>
</div>
Vue.createApp({
methods:{
clickCallback(event) {
console.log('click')
}
}
}).mount("#app")
在上面的代码中,将 v-on
指令应用于 click
事件上,同时给了一个方法名 clickCallback
作为事件的回调函数,当 DOM
触发 click
事件时会进入在 methods
中定义的 clickCallback
方法中。event
参数是当前事件的 Event
对象。
如果想在事件中传递参数,可以采用内联语句,该语句可以访问一个 $event
属性,如示例代码2-2-17所示。
<div id="app">
<button @click="clickCallback('hello',$event)">点我</button>
</div>
Vue.createApp({
methods:{
clickCallback(params,event) {
console.log(params,event)
}
}
}).mount("#app")
v-on
指令用在普通元素上时,只能监听原生 DOM
事件,例如 click
事件、touch
事件等,用在自定义元素组件上时,也可以监听子组件触发的自定义事件,如示例代码2-2-18所示。
<cuscomponent @cusevent="handleThis"></cuscomponent>
<!-- 内联语句 -->
<cuscomponent @cusevent="handleThis(123, $event)"></cuscomponent>
自定义事件一般用在组件通信中,我们会在后面的章节讲解,在使用 v-on
监听原生 DOM
事件时,可以添加一些修饰符并有选择性地执行一些方法或者程序逻辑:
-
.stop
:阻止事件继续传播,相当于调用event.stopPropagation()
。 -
.prevent
:告诉浏览器不要执行与事件关联的默认行为,相当于调用event.preventDefault()
。 -
.capture
:使用事件捕获模式,即元素自身触发的事件先在这里处理,然后才交由内部元素进行处理。 -
.self
:只有当event.target
是当前元素自身才触发处理函数。 -
.once
:事件只会触发一次。 -
.passive
:告诉浏览器不阻止与事件关联的默认行为,相当于不调用event.preventDefault()
。与prevent
相反。 -
.left
、.middle
、.right
:分别对应鼠标左键、中键、右键的单击触发。 -
.{keyAlias}
:只有当事件是由特定按键触发时才触发回调函数。
下面举一个使用 .prevent
的例子,如示例代码2-2-19所示。示例代码2-2-19 v-on
指令修饰符
<div id="app">
<a @click.prevent="clickCallback" href="https://www.qq.com">点我</a>
</div>
Vue.createApp({
methods:{
clickCallback(event) {
// 相当于在这里调用了event.preventDefault()方法
console.log(event)
}
}
}).mount("#app")
对于 <a>
标签而言,它的浏览器默认事件行为就是单击后打开 href
属性所配置的链接,设置了 .prevent
修饰符之后,就相当于在 click
回调方法中首先调用了 event.preventDefault()
方法,当单击 <a>
标签时就只会触发 @click
所绑定的事件,不会再触发默认事件了。
vue
中 v-on
是可以绑定多个方法:
-
v-on
绑定多个方法(采用的是对象形式)<button v-on="{click: clickMethds, mousemove: mouseMethods}">按钮<button>
-
一个事件绑定多个方法
<button @click="click1,click2"></button>
v-model
最后讲解一下 v-model
指令,一般用在表单元素上,例如 <input type="text"/>
、<input type="checkbox" />
、<input type="radio" />
、<select>
等和 自定义组件,以便实现双向绑定。v-model
会忽略所有表单元素的 value
、checked
和 selected
属性的初始值,因为它选择 Vue
实例中 data
设置的数据作为具体的值,如示例代码2-2-20所示。
<div id="app">
<input v-model="message">
<p>hello {{message}}</p>
</div>
Vue.createApp({
data() {
return {message:'Jack'}
}
}).mount("#app")
在这个例子中,直接在浏览器 <input>
中输入别的内容,下面的 <p>
中的内容会跟着变化。这就是双向数据绑定。
将 v-model
应用在表单输入元素上时,Vue
内部会为不同的输入元素使用不同的属性并触发不同的事件:
-
text
和textarea
使用value
属性和input
事件。 -
checkbox
和radio
使用checked
属性和change
事件。 -
select
字段将value
作为属性并将change
作为事件。
下面的例子是 v-model
和 v-for
结合实现 <select>
的双向数据绑定,如示例代码2-2-21所示。
<div id="app">
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
Vue.createApp({
data() {
return {
selected: 'Jack',
options: [
{ text: 'PersonOne', value: 'Jack' },
{ text: 'PersonTwo', value: 'Tom' },
{ text: 'PersonThree', value: 'Leo' }
]
}
}
}).mount("#app")
渲染效果如图2-8所示。

在切换 <select>
时,页面上的值会动态地改变,这就是结合 <select>
的表现。另外,在文本区域 <textarea>
,直接使用插值表达式是不会有双向绑定效果的,代码如下:
<textarea>{{text}}</textarea>
这时需要使用 v-model
来代替,代码如下:
<textarea v-model="text"></textarea>
若想单独给某些 input
输入元素绑定值,而不想要双向绑定的效果,则可以直接用 v-bind
指令给 value
赋值,代码如下:
<input v-bind:value="text"></input>
使用 v-model
时,可以添加一些修饰符来有选择性地执行一些方法或者程序逻辑:
-
.lazy
:在默认情况下,v-model
会同步输入框中的值和数据。可以通过这个修饰符,转变为在输入框的change
事件中再进行值和数据同步。 -
.number
:自动将用户的输入值转化为number
类型。 -
.trim
:自动过滤用户输入的首尾空格。
v-model
指令也可以绑定给自定义的 Vue
组件使用,在后文将具体讲解。
默认情况下, 当你在 |
TODO 自定义组件的 v-model
v-memo
v-memo
用于告诉 Vue
仅在某些依赖发生变化时才重新渲染某个 DOM
元素或组件。当指定的条件不发生变化时,Vue
会跳过该部分的重新渲染,从而节省计算资源。
v-memo
是 Vue 3
中引入的指令,它的作用是在列表渲染时,在某种场景下跳过新的虚拟 DOM
的创建提升性能,使用方法如示例代码2-2-22所示。
<div v-memo="[valueA, valueB]">
...
</div>
当组件重新渲染的时候,如果 valueA
与 valueB
都维持不变,那么对这个 <div>
以及它的所有子节点的更新都将被跳过。事实上,即使是虚拟 DOM
的 VNode
创建也将被跳过,因为子树的记忆副本可以被重用。
v-memo
指令主要结合 v-for
一起使用,而且必须作用在同一个元素上,如示例代码2-2-23所示。
<div id="app">
<button @click="selected = '3'">点我</button>
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
</div>
</div>
Vue.createApp({
data() {
return {
selected: '1',
list: [
{ id: '1'},
{ id: '2'},
{ id: '3'},
{ id: '4'},
]
}
}
}).mount("#app")
在这个例子中,只有以下 div
会被重新渲染:
-
item.id === '1'(初始值为
true
,现在为false
,所以需要重新渲染)。 -
item.id === '3'(初始值为
false
,现在为true
,所以需要重新渲染)。 -
item.id === '2' 和 item.id === '4' 在两次渲染之间没有变化,因此它们的 div 不会被重新渲染。
在之前讲解 v-for
指令时,我们知道 key
属性给每个列表元素分配了唯一的键值,这样使得 Vue
在做前后的虚拟 DOM
改变对比时更加高效,但前提是需要创建新的虚拟 DOM
,当我们使用了 v-memo
时,如果当前的列表元素所对应的 v-memo
没有改变,那么这部分虚拟 DOM
也不会重新创建,减少了过多的虚拟 DOM
创建,也能在一定程度上提升性能。当然,这在列表条数很少时体现得并不明显,但是当列表很长时,也就能体现出性能差异了。
v-memo
的引入也使得在大量列表渲染方面,Vue 3
离成为最快的主流前端框架更近了一步。
v-cloak
v-cloak
是 Vue.js
提供的一个指令,用于保持 Vue
模板的占位符内容在 Vue
完全初始化之前不可见。通常,它用于在页面加载期间避免显示模板的未处理内容,直到 Vue
实例完全渲染完毕。
v-cloak 的作用:
-
隐藏 Vue 模板内容:在
Vue
完全挂载之前,带有v-cloak
指令的元素和它们的内容会保持隐藏。它通常与CSS
配合使用,通过display: none
来隐藏这些内容。 -
解决页面闪烁问题:当你将
Vue
渲染到页面时,页面上可能会闪烁显示未处理的模板内容,尤其是在Vue
实例加载慢或有较大资源时。使用v-cloak
可以确保Vue
完全加载之后,页面才显示模板内容。
<template>
<div id="app" v-cloak>
<p>{{ message }}</p>
</div>
</template>
<style>
[v-cloak] {
display: none;
}
</style>
v-once
v-once
是 Vue.js
提供的一个指令,用于在模板中标记某部分内容只渲染一次。也就是说,使用 v-once
的元素及其子元素会在第一次渲染时渲染一次,之后即使数据变化,该部分内容也不会重新渲染。这个指令在性能优化和处理一些静态内容时非常有用。
何时使用 v-once
:
-
静态内容:如果某些部分的数据或结构在应用生命周期内是固定的,不会根据状态变化,使用
v-once
可以避免不必要的重新渲染。 -
性能优化:对于大型应用,特别是有许多内容固定的部分,使用
v-once
可以减轻Vue
的渲染负担,提高性能,尤其是在数据频繁变化时。
v-pre
v-pre
是 Vue.js
提供的一个指令,用于跳过 Vue
的编译过程,直接渲染原始 HTML
标签和内容。简单来说,v-pre
用来标记某些部分的模板内容应该被 Vue
原样渲染,而不经过 Vue
的模板编译和数据绑定。这通常用于静态内容,尤其是在模板中嵌套 HTML
或一些需要被原样渲染的字符串时。
v-slot
v-slot
是 Vue.js
提供的一个指令,用于在插槽(slot
)中传递内容和动态数据。它是 Vue 2.6
及以上版本中引入的插槽语法,旨在增强插槽的灵活性和可控性。通过 v-slot
,开发者可以传递数据给插槽并在父组件中动态渲染插槽内容。
插槽是 Vue
提供的一种机制,用来在父组件中传递内容到子组件中。插槽可以是默认插槽(没有名字的插槽)或具名插槽(有名字的插槽)。v-slot
指令的主要作用是让父组件控制子组件中插槽的内容。
-
默认插槽
如果插槽没有名字,可以直接使用
v-slot
来绑定数据或内容。<!-- ParentComponent.vue --> <template> <child-component> <template v-slot> <p>这是从父组件传递过来的插槽内容。</p> </template> </child-component> </template>
-
具名插槽
如果插槽有名字,可以通过
v-slot:name
来指定插槽的名称。<!-- ParentComponent.vue --> <template> <child-component> <template v-slot:header> <h1>这是头部插槽内容</h1> </template> <template v-slot:footer> <p>这是底部插槽内容</p> </template> </child-component> </template>
-
插槽作用域
通过
v-slot
可以将子组件的某些数据传递给父组件的插槽,形成插槽的 “作用域”。子组件将数据暴露给父组件,父组件可以通过作用域来访问这些数据。<!-- ChildComponent.vue --> <template> <div> <slot :message="message"></slot> </div> </template> <script> export default { data() { return { message: '来自子组件的数据' } } } </script>
<!-- ParentComponent.vue --> <template> <child-component> <template v-slot:default="slotProps"> <p>{{ slotProps.message }}</p> </template> </child-component> </template>
在上面的例子中,子组件通过
slot
将message
作为属性暴露给插槽。父组件通过v-slot:default="slotProps"
访问这个message
属性,并在插槽中显示它。
在 Vue 2.6 版本及以上,你可以使用更简洁的语法,去掉 template
标签。如果插槽没有作用域数据,也可以不写 v-slot
。
<child-component v-slot:header>
<h1>这是头部内容</h1>
</child-component>
<child-component v-slot>
<p>这是默认插槽内容</p>
</child-component>
指令的动态参数
在使用 v-bind
或者 v-on
指令时,冒号后面的字符串被称为指令的参数,代码如下:
<a v-bind:href="url">...</a>
这里 href
是参数,告知 v-bind
指令将该元素的 href
属性与表达式 url
的值绑定。
<a v-on:click="doSomething">...</a>
在这里 click
是参数,告知 v-on
指令绑定哪种事件。
把用方括号括起来的 JavaScript 表达式作为一个 v-bind
或 v-on
指令的参数,这种参数被称为动态参数。
v-bind
指令的动态参数代码如下:
<a v-bind:[attributeName]="url"> ... </a>
代码中的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果 Vue
实例有一个 data
属性 attributeName
,其值为 href
,那么这个绑定将等价于 v-bind:href
。
v-on
指令的动态参数代码如下:
<button v-on:[event]="doThis"></button>
代码中的 event
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果 Vue
实例有一个 data
属性 event
,其值为 click
,那么这个绑定将等价于 v-on:click
。
动态参数表达式有一些语法约束,因为某些字符(例如空格和引号)放在 HTML
属性名里是无效的,所以要尽量避免使用这些字符。例如,下面的代码在参数中添加了空格,所以是无效的:
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value"> ... </a>
变通的办法是使用没有空格或引号的表达式,或用计算属性替代这种复杂的表达式。另外,如果在 DOM 中使用模板(直接在一个 HTML 文件中编写模板需要回避大写键名),需要注意浏览器会把属性名全部强制转为小写 ,代码如下:
<!-- 在 DOM 中使用模板时这段代码会被转换为 'v-bind:[someattr]' -->
<a v-bind:[someAttr]="value"> ... </a>
至此,与 Vue.js
模板语法有关的内容就讲解完了。模板语法是逻辑和视图之间沟通的桥梁,是 Vue
中实现页面逻辑最重要的知识,也是用得最多的知识,希望读者掌握好这部分知识,为后面 Vue
其他相关知识的学习打下坚实的基础。