Vue——模板语法
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层组件实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应性系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
一、插值
1、文本
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:
1 | < span >Message: {{ msg }}</ span > |
Mustache 标签将会被替代为对应组件实例中 msg
property 的值。无论何时,绑定的组件实例上 msg
property 发生了改变,插值处的内容都会更新。
2、原始 HTML(v-html)
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html
指令:
指令 (Directives) 是带有 v-
前缀的特殊 attribute。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | < div id="app"> < p >Using mustaches: {{ rawHtml }}</ p > < p >Using v-html directive: < span v-html="rawHtml"></ span ></ p > </ div > < script > const Counter = { data() { return { rawHtml: "< a href=''>hello</ a >" } } } vm = Vue.createApp(Counter).mount('#app') </ script > |
3、value 值(v-model)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < div id="app"> <!-- 设置vue可以操作的html内容范围,值一般就是css的id选择器。 --> < p >{{ msg }}</ p > < p >< input type="text" v-model="msg"></ p > </ div > < script > const Counter = { data() { return { msg: "hello world" } } } vm = Vue.createApp(Counter).mount('#app') </ script > |
4、Attribute(v-bind)
Mustache 语法不能在 HTML attribute 中使用,然而,可以使用 v-bind
指令进行绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | < div id="app"> < p >< a :href="link">{{site}}</ a ></ p > < p >< a v-bind:href="link">{{site}}</ a ></ p > < p > < input type="text" v-model="site"> < input type="text" v-model="link"> </ p > </ div > < script > const Counter = { data() { return { site: "百度", link: "http://www.baidu.com" } } } vm = Vue.createApp(Counter).mount('#app') </ script > |
v-bind:属性名
简写格式 :属性名
指令的意思是:“将这个元素节点的 href
attribute 和 Vue 实例的 link
property 保持一致”。
5、使用 JavaScript 表达式
迄今为止,在我们的模板中,我们一直都只绑定简单的 property 键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | < div id="app"> < p > {{ number + 1 }}</ p > < p > {{ ok ? 'YES' : 'NO' }}</ p > < p > {{ msg.split('').reverse().join('') }}</ p > < div v-bind:id="'list-' + id">{{id}}</ div > </ div > < script > const Counter = { data() { return { number:100, ok:"NO", msg: "hello world", id:3, } } } vm = Vue.createApp(Counter).mount('#app') </ script > |
这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,不能是js语句,所以下面的例子都不会生效。
1 2 3 4 5 | <!-- 这是语句,不是表达式:--> {{ var a = 1 }} <!-- 流控制也不会生效,请使用三元表达式 --> {{ if (ok) { return message } }} |
二、样式绑定(class与style)
1、class属性操作
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute,所以我们可以用 v-bind
处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
(1)对象语法
我们可以传给 :class
(v-bind:class
的简写) 一个对象,以动态地切换 class:
1 | < div :class="{ active: isActive }"></ div > |
上面的语法表示 active
这个 class 存在与否将取决于数据 property isActive
的 truthiness。
你可以在对象中传入更多字段来动态切换多个 class。此外,:class
指令也可以与普通的 class
attribute 共存。当有如下模板:
1 2 3 4 | < div class="static" :class="{ active: isActive, 'text-danger': hasError }" ></ div > |
和如下 data:
1 2 3 4 5 6 | data() { return { isActive: true, hasError: false } } |
渲染结果为:
1 | < div class="static active"></ div > |
当 isActive
或者 hasError
变化时,class 列表将相应地更新。例如,如果 hasError
的值为 true
,class 列表将变为 "static active text-danger"
。
绑定的数据对象不必内联定义在模板里:
1 | < div :class="classObject"></ div > |
1 2 3 4 5 6 7 8 | data() { return { classObject: { active: true, 'text-danger': false } } } |
渲染的结果和上面一样。我们也可以在这里绑定一个返回对象的计算属性。这是一个常用且强大的模式:
1 | < div :class="classObject"></ div > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | data() { return { isActive: true, error: null } }, computed: { classObject() { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } } |
(2)数组语法
我们可以把一个数组传给 :class
,以应用一个 class 列表:
1 | < div :class="[activeClass, errorClass]"></ div > |
1 2 3 4 5 6 | data() { return { activeClass: 'active', errorClass: 'text-danger' } } |
渲染的结果为:
1 | < div class="active text-danger"></ div > |
如果你想根据条件切换列表中的 class,可以使用三元表达式:
1 | < div :class="[isActive ? activeClass : '', errorClass]"></ div > |
这样写将始终添加 errorClass
,但是只有在 isActive
为 truthy[1] 时才添加 activeClass
。
不过,当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
1 | < div :class="[{ active: isActive }, errorClass]"></ div > |
2、style属性操作
(1)对象语法
:style
的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:
1 | < div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></ div > |
1 2 3 4 5 6 | data() { return { activeColor: 'red', fontSize: 30 } } |
直接绑定到一个样式对象通常更好,这会让模板更清晰:
1 | < div :style="styleObject"></ div > |
1 2 3 4 5 6 7 8 | data() { return { styleObject: { color: 'red', fontSize: '13px' } } } |
同样的,对象语法常常结合返回对象的计算属性使用。
(2)数组语法
:style
的数组语法可以将多个样式对象应用到同一个元素上:
1 | < div :style="[baseStyles, overridingStyles]"></ div > |
三、条件渲染
1、v-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。也可以用 v-else
添加一个“else 块”:
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 | < div id="app"> < div > < h3 >if-else</ h3 > < div v-if="age>18">成年影视</ div > < div v-else>青少年影视</ div > <!-- if和else要紧挨着--> < input type="text" v-model="age"> </ div > < h3 >if-else-if</ h3 > < div > < div v-if="score>90">优秀</ div > < div v-else-if="score>80">良好</ div > < div v-else-if="score>60">及格</ div > < div v-else>不及格</ div > < input type="text" v-model="score"> </ div > </ div > < script > Vue.createApp({ data() { return { age: 10, score: 80, } }, }).mount('#app') </ script > |
2、v-show
另一个用于条件性展示元素的选项是 v-show
指令。用法大致一样:
1 | < h1 v-show="ok">Hello!</ h1 > |
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS property display
。
注意,
v-show
不支持<template>
元素,也不支持v-else
。
3、v-if
vs v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
四、循环渲染(v-for)
1、数组循环
我们可以用 v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items 是源数据数组,而 item
则是被迭代的数组元素的别名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | < div id="app"> < ul > <!-- v-for 还支持一个可选的第二个参数,即当前项的索引。--> < li v-for="stu,index in students">序号:{{index}} 姓名: {{stu.name}} 年龄:{{stu.age}}</ li > </ ul > </ div > < script > Vue.createApp({ data() { return { students:[{"name":"yuan","age":22},{"name":"rain","age":24},{"name":"eric","age":21}] } }, }).mount('#app') </ script > |
2、对象循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | < div id="app"> < ul > <!-- 提供第二个的参数为 property 名称 (也就是键名 key)--> < li v-for="val,key in student">{{key}} ::: {{val}}</ li > </ ul > </ div > < script > Vue.createApp({ data() { return { student:{"name":"yuan","age":22} } }, }).mount('#app') </ script > |
3、练习 —— 将所有书籍中价格大于100元的背景变蓝色
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script src="https://cdn.bootcdn.net/ajax/libs/vue/3.1.2/vue.global.js"></ script > < style > body { font-size: 14px; } table, tr, th, td { border: 1px solid red; border-collapse: collapse; /* 合并边框 */ } th, td { width: 200px; text-align: center; /* 文本水平居中 */ height: 30px; line-height: 30px; } input { width: 80px; } .active{ background-color: lightskyblue; } </ style > </ head > < body > < div id="app"> < table > < tr > < th >序号</ th > < th >书籍名称</ th > < th >价格</ th > </ tr > < tr v-for="book,index in books" :class="book.price > 100?active:''"> < td >{{index + 1}}</ td > < td >{{book.name}}</ td > < td >{{book.price}}</ td > </ tr > </ table > </ div > < script > Vue.createApp({ data() { return { books: [ {"name": "python入门", "price": 150}, {"name": "python进阶", "price": 100}, {"name": "python高级", "price": 75}, {"name": "python研究", "price": 60}, {"name": "python放弃", "price": 110}, ], active:"active" } }, }).mount('#app') </ script > </ body > </ html > |
注意我们不推荐在同一元素上使用 v-if
和 v-for
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现