Vue2 模板语法与样式绑定
一、插值语法
1. 文本插值 {``{ }}
在标签的内容区域使用双大括号,可以把 data 中的数据渲染出来:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Vue2 文本插值</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue'
}
});
</script>
</body>
</html>
页面渲染结果:Hello Vue。
使用规则:
{``{ }}只能写在标签的内容区域,不能写在标签属性中。给属性绑定值要用v-bind(见下文)。- 内部支持 JavaScript 表达式:
{``{ number + 1 }}、{``{ message.toUpperCase() }}、{``{ isOk ? '是' : '否' }}、{``{ arr.join('、') }}。 - 内部不能写语句:
{``{ if (x) { return 1 } }}会直接报错,因为插值里只接受表达式,不接受语句。 - 插值对应的 data 发生变化时,页面会自动更新,这是 Vue 的响应式机制。
2. v-text 与 v-html
v-text 和 v-html 都是指令,用来把数据写进标签内容,与插值的作用有重叠,但行为不同:
v-text:以纯文本方式渲染,等价于 JS 的innerText。用它替代插值可以避免页面加载瞬间闪现原始{``{ }}(闪烁问题)。v-html:把内容当作 HTML 解析后渲染,等价于innerHTML。
html
<div id="app">
<div v-text="content"></div>
<div v-html="content"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
content: '<strong>加粗文字</strong>'
}
});
</script>
第一个 div 显示原样字符串 <strong>加粗文字</strong>,第二个 div 显示加粗后的「加粗文字」。
安全要求:v-html 会解析传入的 HTML,包括其中的脚本逻辑。不要把用户可输入的内容直接传给 v-html,否则存在 XSS(跨站脚本)攻击风险。需要展示富文本时,应先用库(如 DOMPurify)做过滤再渲染。
3. v-once、v-pre、v-cloak
v-once:元素只渲染一次,之后数据再变化也不再更新。适合渲染后不再变化的静态内容,可以减少不必要的更新开销。v-pre:跳过当前元素及其所有子元素的编译,内容原样输出,不做插值处理。适合展示原始模板文本,也能加快编译速度。v-cloak:配合 CSS 使用,解决插值闪烁。原理是:在 Vue 完成编译前,带有v-cloak的元素被 CSS 隐藏;编译完成后 Vue 自动移除v-cloak属性,元素显示。
html
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app">
<div v-cloak>{{ message }}</div>
</div>
二、指令
指令是 Vue 模板语法的主体。所有指令都以 v- 开头,作用是在元素上绑定特定的行为。
1. 条件渲染 v-if / v-else-if / v-else
v-if 根据表达式的真假决定元素是否渲染。为假时元素不会出现在 DOM 中。
html
<div id="app">
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
</div>
<script>
new Vue({
el: '#app',
data: {
score: 75
}
});
</script>
规则:
v-if、v-else-if、v-else必须是相邻的兄弟元素,中间不能插入其他标签,否则v-else无法正确匹配。- 如果一次要控制多个相邻元素,可以配合
<template>标签包裹,v-if写在<template>上,<template>本身不会渲染成 DOM。
html
<template v-if="isShow">
<h3>标题</h3>
<p>段落一</p>
<p>段落二</p>
</template>
2. v-show 与 v-if 的区别
v-show 也是条件显示,但行为不同:v-show 为假时元素仍然渲染在 DOM 中 ,只是被加上 display: none。
html
<p v-show="isShow">这段文字由 v-show 控制</p>
| 对比项 | v-if | v-show |
|---|---|---|
| 为假时的行为 | 不渲染到 DOM | 渲染到 DOM,用 display:none 隐藏 |
| 切换成本 | 需要创建/销毁元素,成本高 | 只切换样式,成本低 |
| 初次渲染 | 为假时不做渲染,适合懒加载场景 | 无论真假都渲染 |
| 使用场景 | 切换不频繁、初始为假的内容 | 高频切换的内容 |
3. 列表渲染 v-for
v-for 用来遍历数组、对象和数字,生成一组元素。
html
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.id">
{{ index }} - {{ item.name }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
list: [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
]
}
});
</script>
规则:
- 遍历数组时写
v-for="item in list",需要下标时写v-for="(item, index) in list"。 - 遍历对象时写
v-for="(value, key, index) in obj"。 - 遍历数字时写
v-for="n in 10",n 从 1 开始。 - 必须给每个循环项绑定唯一的
:key。key帮助 Vue 在列表变化时复用和识别节点,不要用 index 作为 key,否则插入、删除、排序时可能出现渲染错乱。key 应使用数据自身的唯一标识(如 id)。
4. 事件绑定 v-on
v-on 给元素绑定事件,简写为 @。
html
<div id="app">
<button @click="count++">点击加一:{{ count }}</button>
<button @click="say('你好')">传参调用</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
say(msg) {
console.log(msg);
}
}
});
</script>
- 事件处理函数写在
methods中,通过方法名调用。 - 传参时写
@click="say('你好')"。 - 需要事件对象时写
@click="say($event)"。 - 常用修饰符:
.stop(阻止冒泡)、.prevent(阻止默认行为)、.once(只触发一次)、.enter(回车键触发)等。
html
<form @submit.prevent="onSubmit">
<button type="submit">提交</button>
</form>
5. 双向绑定 v-model
v-model 用于表单元素,实现数据与视图的双向绑定:数据变视图变,用户输入后视图变数据也变。
html
<div id="app">
<input v-model="username" placeholder="请输入用户名">
<p>当前输入:{{ username }}</p>
<input type="checkbox" v-model="checked"> 已阅读协议
<p>选中状态:{{ checked }}</p>
<select v-model="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
<p>选择城市:{{ city }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
username: '',
checked: false,
city: 'beijing'
}
});
</script>
v-model 的底层原理:
- 普通文本输入框:
value属性 +input事件。 - 复选框、单选按钮:
checked属性 +change事件。 - 下拉选择:
value属性 +change事件。
常用修饰符:
.lazy:把同步时机从input事件改为change事件,即失去焦点或回车时才更新数据。.number:把输入值自动转成数字类型。.trim:自动去除输入内容首尾空格。
html
<input v-model.number="age" placeholder="年龄">
<input v-model.trim="name" placeholder="姓名">
6. 属性绑定 v-bind
v-bind 把 data 中的数据绑定到标签属性上,简写为 :。它是 class / style 绑定的基础。
html
<div id="app">
<img :src="imgUrl" :alt="altText">
<a :href="link">链接</a>
</div>
<script>
new Vue({
el: '#app',
data: {
imgUrl: 'https://example.com/logo.png',
altText: 'Logo',
link: 'https://example.com'
}
});
</script>
- 布尔属性(如
disabled、checked)绑定false时,属性会被移除;绑定true时,属性会出现。 - 不带参数的
v-bind可以把一个对象的所有属性一次性绑定到元素上:
html
<div v-bind="{ id: 'box1', title: '提示' }"></div>
三、绑定 class
通过 v-bind:class(简写 :class)可以动态控制元素的 class。与原生 class 属性可以共存。
1. 对象语法
:class 的值是一个对象:键是类名,值是布尔表达式。值为真时该类名生效。
html
<div id="app">
<p :class="{ active: isActive, 'text-danger': hasError }">状态文字</p>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
hasError: false
}
});
</script>
渲染结果:<p class="active">状态文字</p>。
- 类名是合法标识符时可以不加引号(如
active)。 - 类名包含短横线等特殊字符时必须加引号(如
'text-danger')。 - 当
isActive变为false时,active类自动移除。
2. 数组语法
:class 的值是一个数组,数组中的每一项都会作为类名应用。
html
<p :class="[baseClass, activeClass]">文字</p>
js
data: {
baseClass: 'text-center',
activeClass: 'text-bold'
}
渲染结果:<p class="text-center text-bold">文字</p>。
数组中的项可以是字符串、三元表达式、对象,三者可以混用:
html
<p :class="[baseClass, isActive ? 'active' : '', { 'text-danger': hasError }]">文字</p>
3. 与计算属性配合
对象里的逻辑变复杂时,可以把对象计算好放在计算属性里,模板保持简洁:
html
<p :class="classObject">文字</p>
js
computed: {
classObject() {
return {
active: this.isActive,
'text-danger': this.hasError
};
}
}
4. 在组件上绑定 class
:class 写在自定义组件标签上时,会作为组件根元素 的 class,不需要组件内部单独接收。这是 Vue 2 中 class 和 style 绑定区别于普通属性的地方(普通属性需要组件用 props 接收)。
四、绑定 style
v-bind:style(简写 :style)用来动态绑定内联样式。
1. 对象语法
:style 的值是一个对象,键是 CSS 属性名,值是属性值。属性名用驼峰命名(fontSize)或加引号的短横线命名('font-size')都可以。
html
<div id="app">
<p :style="{ color: textColor, fontSize: fontSize + 'px', 'font-weight': isBold ? 'bold' : 'normal' }">
样式绑定示例
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
textColor: 'red',
fontSize: 20,
isBold: true
}
});
</script>
渲染结果:<p style="color: red; font-size: 20px; font-weight: bold;">样式绑定示例</p>。
2. 数组语法
:style 的值也可以是数组,数组中的多个对象会合并,后者的同名属性覆盖前者。
html
<p :style="[baseStyle, overrideStyle]">文字</p>
js
data: {
baseStyle: { color: 'blue', fontSize: '16px' },
overrideStyle: { color: 'red' }
}
渲染结果:<p style="color: red; font-size: 16px;">文字</p>。
3. 自动加前缀与多重值
- 需要浏览器前缀的 CSS 属性(如
transform),Vue 会检测当前浏览器支持情况,自动加上-webkit-、-moz-等前缀。 - 从 Vue 2.3.0 开始,
:style的属性值可以是一个数组,表示多重值。浏览器会使用它支持的那一个值:
html
<p :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">文字</p>
4. 在组件上绑定 style
与 class 一样,:style 写在组件标签上也会应用到组件根元素。
五、小结
| 语法 | 简写 | 用途 |
|---|---|---|
{``{ }} |
无 | 标签内容插值 |
v-text / v-html |
无 | 以文本 / HTML 方式渲染内容 |
v-if / v-show |
无 | 条件渲染 |
v-for |
无 | 列表渲染 |
v-on |
@ |
事件绑定 |
v-model |
无 | 表单双向绑定 |
v-bind |
: |
属性绑定 |
:class |
: |
动态 class(对象 / 数组语法) |
:style |
: |
动态 style(对象 / 数组语法) |
选择建议:
- 内容是动态数据 → 插值或
v-text;需要解析 HTML →v-html(注意 XSS 风险)。 - 切换不频繁或初始不渲染 →
v-if;高频切换 →v-show。 - 列表渲染必须绑定唯一
key,避免使用 index。 - 样式要动态控制 → 优先使用
:class,class 样式可复用、便于维护;:style适合少量、局部且依赖数据的样式。