1.2 第一个 Vue 组件
本章目标: 亲眼看到“修改状态 → 页面更新”的过程,理解一个 .vue 文件的三个部分。
写一个计数器
把 vue-lab/src/App.vue 替换为:
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
const count = ref(0);
function increment() {
count.value++;
}
function reset() {
count.value = 0;
}
</script>
<template>
<main class="counter">
<h1>我的第一个 Vue 组件</h1>
<p>已点击 {{ count }} 次</p>
<button type="button" @click="increment">加一</button>
<button type="button" @click="reset">重置</button>
</main>
</template>
<style scoped>
.counter {
max-width: 36rem;
margin: 3rem auto;
padding: 1rem;
}
button {
margin-right: 0.75rem;
padding: 0.5rem 1rem;
}
</style>
运行 npm run dev,点击“加一”。数字应递增,点击“重置”应恢复为零。
初始样式
脚手架可能在 main.ts 引入演示用的全局 CSS。如果页面居中方式或颜色与你预期不同,可以移除该演示样式的导入,再观察这里的组件样式。
三个区域分别负责什么
| 区域 | 用途 | 对照你的经验 |
|---|---|---|
<script setup lang="ts"> | 声明状态、函数、导入组件 | UI 背后的代码逻辑 |
<template> | 描述状态如何显示 | 类似 Razor 模板,但由 Vue 编译 |
<style scoped> | 编写当前组件的样式 | CSS 作用范围由编译器辅助限制 |
setup 中顶层声明可以直接用于模板,不需要手动返回。lang="ts" 开启 TypeScript 语法。scoped 不等于 Shadow DOM;它通过选择器标记限制大部分样式影响范围。
状态驱动视图
ref(0) 返回一个 Vue 响应式引用。脚本里通过 .value 读取或修改;模板对顶层 ref 自动解包,所以写 {{ count }}。
一次点击的过程
点击按钮 → 执行 increment → 修改 count.value → Vue 更新对应文本
你不需要先找到 <p>,再手工修改 DOM。页面显示内容由状态推导。
普通变量不会自动刷新页面
let count = 0 能保存数字,但变量变化不会被 Vue 作为响应式依赖追踪。Vue 的 ref 也不是 C# 里的按引用传参关键字。
为什么事件写成 @click
@click="increment" 是 v-on:click="increment" 的简写。Vue 在点击时执行函数,而不是在渲染模板时执行它。
{{ count }} 是文本插值,class="counter" 是普通 HTML 属性,@click 是 Vue 指令。下一阶段会先补齐理解这些表达式所需的前端基础。
练习
增加一个“减一”按钮,并让计数不能小于零。验收:连续点击“减一”时页面最低显示零。
参考答案
在脚本中增加:
function decrement() {
count.value = Math.max(0, count.value - 1);
}
在模板中增加:
<button type="button" @click="decrement" :disabled="count === 0">
减一
</button>
函数保证数据规则,:disabled 表达按钮状态。两者结合,既保护逻辑也让用户看到当前限制。
下一步: HTML、CSS 与浏览器。参考:单文件组件。