Skip to content

20|Vue 模板语法与响应式数据

Vue 的核心是"数据驱动":在 script 中定义数据,在 template 中使用数据,数据变化时页面自动更新。理解 Vue 的模板语法和响应式数据机制,是写出正确组件的前提。

一、文本插值

用双大括号 {{ }} 把数据绑定到模板:

vue
<template>
  <div>
    <h1>{{ appName }}</h1>
    <p>当前用户: {{ user.name }}</p>
    <p>磁盘使用率: {{ usage }}%</p>
  </div>
</template>

<script setup>
const appName = "运维平台";
const user = { name: "admin" };
const usage = 78;
</script>

{{ }} 内部支持简单的 JavaScript 表达式:

vue
<template>
  <div>
    <p>{{ usage > 90 ? '严重' : '正常' }}</p>
    <p>{{ user.name.toUpperCase() }}</p>
  </div>
</template>

但不能写语句(如 iffor、变量赋值),这些需要在 script 中处理。

二、v-bind 绑定属性

HTML 属性不能直接用 {{ }},需要用 v-bind(简写为 :):

vue
<template>
  <div>
    <img :src="logoUrl" :alt="appName">
    <a :href="docsLink" target="_blank">文档</a>
    <input :disabled="isDisabled">
  </div>
</template>

<script setup>
const logoUrl = "/logo.png";
const appName = "运维平台";
const docsLink = "https://docs.example.com";
const isDisabled = true;
</script>

:disabled="isDisabled" 中,isDisabledtruedisabled 属性存在,是 false 时属性不存在。

对于布尔属性(disabledreadonlychecked 等),绑定 truthy/falsy 值即可控制属性有无。

绑定 class

vue
<template>
  <div :class="{ active: isActive, error: hasError }">
    状态卡片
  </div>
</template>

<script setup>
const isActive = true;
const hasError = false;
</script>

对象语法:{ 类名: 布尔值 },值为 true 时添加该类。上面的例子渲染为 class="active"

数组语法(多个类动态组合):

vue
<div :class="[baseClass, statusClass]"></div>

绑定 style

vue
<template>
  <div :style="{ color: textColor, fontSize: size + 'px' }">
    动态样式
  </div>
</template>

<script setup>
const textColor = "#ff4d4f";
const size = 16;
</script>

CSS 属性名用驼峰(fontSize)或短横线加引号('font-size')。

三、v-on 事件绑定

v-on(简写为 @)监听 DOM 事件:

vue
<template>
  <button @click="count++">点击 {{ count }} 次</button>
</template>

<script setup>
import { ref } from "vue";

const count = ref(0);
</script>

事件处理可以写内联表达式,也可以调用方法:

vue
<template>
  <button @click="handleClick">提交</button>
  <button @click="handleSubmit('param')">带参提交</button>
</template>

<script setup>
function handleClick() {
  console.log("点击了按钮");
}

function handleSubmit(id) {
  console.log("提交:", id);
}
</script>

事件修饰符

vue
<!-- 阻止默认行为 -->
<form @submit.prevent="handleSubmit">...</form>

<!-- 阻止冒泡 -->
<div @click.stop="handleDiv">...</div>

<!-- 只触发一次 -->
<button @click.once="init">初始化</button>

<!-- 组合使用 -->
<a @click.stop.prevent="handleLink">链接</a>

四、响应式数据

ref

ref 把普通值包装成响应式对象:

vue
<script setup>
import { ref } from "vue";

const count = ref(0);           // 包装数字
const message = ref("hello");   // 包装字符串
const visible = ref(true);      // 包装布尔值

// 在 script 中读取/修改要用 .value
console.log(count.value);       // 0
count.value++;

// 在 template 中直接使用,不需要 .value
// <p>{{ count }}</p>
</script>

ref 的返回值是一个对象,.value 存着实际值。模板中 Vue 会自动解包,不需要写 .value

reactive

reactive 把对象变成响应式:

vue
<script setup>
import { reactive } from "vue";

const server = reactive({
  hostname: "web-01",
  status: "running",
  cpu: 45,
});

// 直接修改属性,不需要 .value
server.status = "stopped";
server.cpu = 78;
</script>

reactive 只对对象有效(包括数组、Map、Set),对原始值(string、number、boolean)无效。reactive 的属性访问和修改不需要 .value

ref vs reactive 的选择

场景推荐
单个原始值(数字、字符串、布尔)ref
对象、数组reactiveref
需要解构或重新赋值整个对象refreactive 重新赋值会失去响应性)

实际项目中 ref 使用更普遍,因为统一使用 .value 比混用两种风格更清晰。对象也可以用 ref 包装:

js
const server = ref({ hostname: "web-01", status: "running" });

// 修改属性
server.value.status = "stopped";

// 替换整个对象
server.value = { hostname: "web-02", status: "running" };

五、常见错误

在 script 中访问 ref 忘记 .value

js
const count = ref(0);

// 错误
console.log(count);       // RefImpl 对象
console.log(count + 1);   // NaN

// 正确
console.log(count.value); // 0

解构 reactive 对象失去响应性

js
const server = reactive({ hostname: "web-01", status: "running" });

// 错误:解构后变成普通变量,不再响应
const { hostname, status } = server;
status = "stopped";   // 不会触发页面更新

// 正确:用 toRefs
import { toRefs } from "vue";
const { hostname, status } = toRefs(server);
status.value = "stopped";   // 正常响应

模板中写复杂表达式

vue
<!-- 不建议:模板里写太长的逻辑 -->
<p>{{ items.filter(i => i.status === 'running').map(i => i.name).join(', ') }}</p>

<!-- 建议:移到 computed 或方法中 -->
<p>{{ runningNames }}</p>