模板语法:指令与数据绑定

第 1 节 概述

在上一篇文章中,我们用 refreactive 定义了响应式数据。

现在的问题是:数据怎么显示到页面上?用户的操作怎么触发数据变化?

Vue 3 的模板语法解决的就是这两个问题。我们用一条主线串起来:

1
数据显示 {{ }} → 属性绑定 : → 条件显示 v-if → 列表循环 v-for → 用户点击 @ → 表单输入 v-model

第 2 节 文本插值

双大括号可以把数据插入到模板中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<script setup lang="ts">
const name = '张三'
const age = 25
</script>

<template>
  <p>姓名{{ name }}</p>
  <p>年龄{{ age }}</p>
  <p>表达式{{ age + 1 }}</p>
</template>

大括号里可以写任意合法的 JavaScript 表达式。

但不要写完整的语句,比如 iffor

第 3 节 属性绑定

3.1 基本用法

v-bind 可以把 HTML 属性绑定到变量:

1
2
3
4
5
6
7
8
9
<script setup lang="ts">
const id = 'container'
const url = 'https://example.com'
</script>

<template>
  <div v-bind:id="id"></div>
  <a v-bind:href="url">链接</a>
</template>
技巧

v-bind 可以简写为 :。这是最常用的写法。

1
2
3
4
<template>
  <div :id="id"></div>
  <a :href="url">链接</a>
</template>

不加 : 的属性是普通字符串,加了 : 的属性会作为变量或表达式解析。

3.2 class 绑定

:class 可以和普通 class 共存,Vue 会自动合并:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<script setup lang="ts">
const isActive = ref(true)
const hasError = ref(false)
</script>

<template>
  <div
    class="base-style"
    :class="{ active: isActive, error: hasError }"
  >
    内容
  </div>
</template>

:class 可以传入对象、数组或组合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<script setup lang="ts">
const classObj = ref({
  active: true,
  'text-white': false,
})

const classArr = ref(['px-4', 'py-2'])
</script>

<template>
  <div :class="classObj"></div>
  <div :class="classArr"></div>
  <div :class="[classObj, classArr]"></div>
</template>

3.3 style 绑定

:style 的用法和 :class 类似:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<script setup lang="ts">
const styleObj = ref({
  color: 'red',
  fontSize: '30px',
})
</script>

<template>
  <div :style="styleObj">红色大字</div>
</template>

3.4 绑定多个属性

使用无参数的 v-bind 一次传入多个属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script setup lang="ts">
const attr = ref({
  id: 'container',
  class: 'wrapper',
  style: 'background-color: green',
})
</script>

<template>
  <div v-bind="attr"></div>
</template>

第 4 节 条件渲染

4.1 v-if 系列

v-ifv-else-ifv-else 根据条件决定是否渲染元素:

1
2
3
4
5
6
7
8
9
<script setup lang="ts">
const score = ref(85)
</script>

<template>
  <p v-if="score >= 90">优秀</p>
  <p v-else-if="score >= 60">及格</p>
  <p v-else>不及格</p>
</template>

条件为 false 时,元素根本不会出现在 DOM 中。

4.2 v-show

v-show 也控制显示隐藏,但元素始终存在:

1
2
3
<template>
  <p v-show="isVisible">我只是一直隐藏了</p>
</template>

4.3 v-if vs v-show

对比v-ifv-show
渲染方式条件假时不渲染始终渲染,用 display: none 隐藏
切换开销每次切换都创建/销毁只切换 CSS
初始开销条件假时无开销始终有初始渲染开销
适用场景切换不频繁频繁切换
技巧

如果条件很少变化,用 v-if。如果条件频繁切换(如标签页),用 v-show

第 5 节 列表渲染

v-for 遍历数组或对象:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup lang="ts">
const items = ref(['苹果', '香蕉', '橘子'])
const user = ref({
  姓名: '张三',
  年龄: 18,
  性别: '男',
})
</script>

<template>
  <ul>
    <li v-for="(item, index) in items" :key="index">
      {{ index }}: {{ item }}
    </li>
  </ul>

  <ul>
    <li v-for="(value, key) in user" :key="key">
      {{ key }}: {{ value }}
    </li>
  </ul>
</template>
说明

:key 是 Vue 用来追踪每个元素的标识。遍历时建议提供一个唯一值作为 key,能提升渲染性能。

第 6 节 事件处理

6.1 基本用法

v-on 监听事件,简写为 @

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script setup lang="ts">
const count = ref(0)

function handleClick() {
  count.value++
}
</script>

<template>
  <p>点击次数{{ count }}</p>
  <button @click="handleClick">点击</button>
</template>

也可以直接写内联表达式:

1
2
3
<template>
  <button @click="count++">点击</button>
</template>

6.2 事件修饰符

DOM 事件会经历三个阶段:捕获 → 目标 → 冒泡。

Vue 提供了事件修饰符,简化事件细节的处理:

修饰符作用使用场景
.stop阻止事件冒泡子元素点击不想触发父元素
.prevent阻止默认行为阻止表单提交、链接跳转
.self只有事件源是自己时才触发避免子元素误触
.capture在捕获阶段触发提前拦截事件
.once只触发一次一次性操作,防止重复提交
.passive不调用 preventDefault滚动性能优化

修饰符可以串联:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<template>
  <!-- 阻止冒泡 -->
  <div @click="parentClick">
    <button @click.stop="childClick">点我</button>
  </div>

  <!-- 阻止表单刷新 -->
  <form @submit.prevent="onSubmit">
    <button type="submit">提交</button>
  </form>

  <!-- 阻止右键菜单 -->
  <div @click.right.prevent="openMenu">右键菜单</div>
</template>

6.3 按键修饰符

按键修饰符处理键盘和鼠标操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<template>
  <!-- 回车键提交 -->
  <input @keyup.enter="submit" />

  <!-- Ctrl + Enter -->
  <textarea @keyup.ctrl.enter="send"></textarea>

  <!-- 精确按键组合 -->
  <button @click.ctrl.exact="onCtrlClick">Ctrl + 点击</button>
  <button @click.exact="onClick">仅点击无修饰键</button>
</template>

第 7 节 表单绑定

7.1 v-model 双向绑定

表单元素需要同时做两件事:把数据显示到输入框,用户输入时更新数据。

手动实现需要写两行代码:

1
<input :value="text" @input="event => text = event.target.value" />

Vue 提供了 v-model 简化成一行:

1
<input v-model="text" />

完整示例:

1
2
3
4
5
6
7
8
<script setup lang="ts">
const message = ref('')
</script>

<template>
  <p>你输入的内容{{ message }}</p>
  <input v-model="message" placeholder="输入文字" />
</template>

7.2 修饰符

修饰符作用示例
.number自动转数字<input v-model.number="age" />
.trim去除首尾空格<input v-model.trim="title" />
.lazy失焦时同步,而非输入时<input v-model.lazy="content" />
1
2
3
4
<template>
  <input v-model.number="age" type="number" />
  <input v-model.trim="username" />
</template>

模板语法是 Vue 3 中"视图层“的核心。你现在可以:

  • {{ }}: 显示数据
  • v-ifv-for 控制显示结构
  • @v-model 处理用户操作

但所有代码都写在一个文件里,代码会越来越长。

下一步:怎么把页面拆成独立的小块来管理?