如果你今天才第一次打开 Vue 的文档,大概率会被页面左侧那一长串目录劝退:响应式、指令、组件、生命周期、路由、状态管理……文档当然没错,但信息密度对一个“第一天学 Vue”的人来说太不友好了。没几个人能在第一个下午同时消化这么多概念,硬啃的结果往往是半天之后依然只会照着示例改改文字,一旦报错就完全懵。
我带新人入门 Vue 时习惯把学习拆成一个个按天走的小任务。Day 1 不碰路由、不碰 Pinia、不碰各种花式魔法,只做好一件事:把开发环境跑起来,写一个真正有交互的小页面,并且能说清楚页面上的每一行代码在干什么。这篇文章就把这第一天最该掌握的知识点完整过一遍,按我自己带新人的顺序来排,里面也掺了不少这些年实际踩过的坑。不管是零基础想入门,还是后端转前端想快速上手 Vue,照着走完这一天,你的 Vue 之路就算真正迈出第一步了。
1. 第一天学 Vue,先圈定知识边界
1.1 Vue 到底解决的是什么问题
Vue 是个前端框架,这是你肯定知道的事。但你得先想明白“框架”到底帮你干了什么活,后面学起来才不会跑偏。
在没有框架的时代,我们要在页面里显示一段后端返回的数据,典型操作是这样的:用document.getElementById找到那个 DOM 节点,再手动把数据拼接成 HTML 塞进去。这还不算完,用户改了输入框的值,你要去监听 input 事件,再更新另一个元素的内容。一个页面只有三五个交互点还能忍,等页面一复杂,代码里到处都是“先查 DOM、再改 DOM”的重复劳动,改一个地方漏三处的情况比比皆是。
Vue 的核心思路是:你别去碰 DOM,你只管维护一份数据,页面该长什么样由 Vue 根据这份数据自动算出来。数据变了,页面跟着变;用户操作变了数据,页面也会反向更新。这个“数据和页面自动同步”的机制,就是所有人嘴里说的“响应式”。第一天你不需要把响应式原理完全吃透,但必须建立起这个心智模型:页面是数据的投影,你改数据,页面自己会刷新。
现在网上还能搜到大量 Vue 2 的教程,我的建议是直接忽略它们。Vue 3 从 2020 年发布到现在已经是绝对主流,组合式 API 的写法比 Vue 2 的选项式 API 更符合人的直觉,生态里几乎所有新工具都默认支持 Vue 3。你现在学 Vue 2,等于考完驾照先去学开手动挡旧车,能开但没必要。
1.2 第一天的必学清单与先别碰清单
我见过太多人第一天就跑去研究 vue-router 的动态路由、各种插槽嵌套、store 里的复杂状态管理,结果半天下来把自己学自闭了。第一天你需要的是一条最短路径,让我先把范围划清楚。
| 第一天必须掌握 | 先别碰,等过几天再说 |
|---|---|
| 用 Vite 创建项目、跑起开发服务器 | vue-router 路由,尤其是动态路由和路由守卫 |
模板插值{{ }} | Pinia / Vuex 状态管理 |
| 指令:v-bind、v-on、v-model、v-if、v-for | 插槽 slot 的进阶用法,默认插槽会用即可 |
| ref、reactive 与 computed | 自定义指令、Teleport、KeepAlive |
| 组件拆分、props 传参、emit 触发事件 | SSR、Nuxt、低代码平台这类重型架构 |
这个清单不是我随便拍的。仔细看第一天必学的内容,你会发现它们刚好凑成一个最小的“闭环”:你能创建项目,能渲染数据,能处理用户点击和输入,能实现条件展示和列表循环,能把自己的页面拆成组件。完成这个闭环,你就能写出一个带搜索、待办、留言功能的实用小页面。有了完成感和正反馈,后面学路由、学状态管理才会有底气。
1.3 第一天的实战目标:一个待办事项页面
学任何框架,纯看教程都是最慢的路径。我第一天给新人布置的实战任务很固定:做一个小型待办事项页面,必须包含这些功能:
- 顶部一个输入框,按下回车或点击按钮,把内容添加到下方列表
- 列表可以展示“已完成”和“未完成”两种状态,点击文字可以切换状态
- 每一项后面有一个删除按钮,点击后移除该项
- 一个简单的统计信息,显示还剩几项没完成
这个任务看着小,但它几乎覆盖了第一天所有语法:v-model 做输入绑定、v-for 渲染列表、v-if 做条件展示、@click 处理删除和切换、ref 维护数据、computed 计算剩余数量。后面我讲的每个知识点,你都用这个例子去练一遍,比看十遍文档都管用。
2. 环境搭建:从空目录到页面真正跑起来
2.1 先检查 Node 版本,这步偷懒后面全是坑
很多人的环境配置失败不是操作问题,而是 Node 版本不匹配。Vite 是现在 Vue 项目最常用的构建工具,它对 Node 版本有硬性要求:Vite 5 需要 Node 18 以上,更新的 Vite 6 推荐 Node 20.19 以上。如果你机器上装的是 Node 16,就算项目创建成功,一跑npm run dev也可能报一堆语法错误,新手很容易在这一步直接心态爆炸。
打开终端先检查一下:
node -v npm -v如果版本低于 18,别想着硬磨,直接用 nvm(Node 版本管理器)装一个新版本。nvm 允许你在电脑上装多个 Node 版本,随时切换,比你去系统目录里手动卸载重装干净得多。装好之后重新打开终端再跑一次node -v确认版本号上来了,再继续。
2.2 用 Vite 创建项目并理解目录结构
Vue 官方推荐的脚手架从 Vue CLI 慢慢转移到了 Vite,新手直接选 Vite 没有任何问题。创建一个项目:
npm create vite@latest vue-day1命令执行后它会问你几个问题:框架选 Vue,语法选 JavaScript。这里我不推荐第一天就选 TypeScript——不是说 TS 不好,而是第一天你的注意力应该全部放在“Vue 本身怎么用”上,TS 的类型报错会额外干扰你判断问题。先跑通,再上类型,这是更平滑的学习曲线。
创建完成后进入目录,安装依赖:
cd vue-day1 npm install npm run dev浏览器打开终端里打印的地址,看到一个有 Vue 图标的欢迎页,说明你的开发环境已经通了。趁这个热乎劲,我建议你花两分钟看一下项目里这几个文件是干嘛的,后面改代码才不迷路:
package.json:记录项目依赖了哪些包,以及有哪些脚本命令。npm run dev后面跑的就是这里定义的dev命令。index.html:整个项目的 HTML 入口。Vite 开发模式下,它会在浏览器里加载/src/main.js作为启动文件。/src/main.js:JS 入口,负责创建 Vue 应用并挂载到页面上。里面有一行createApp(App).mount('#app'),意思就是把根组件App渲染到index.html里 id 为app的那个 div 内。/src/App.vue:根组件文件,你现在看到的欢迎页就是它渲染出来的。后面改页面基本就是从它下手。
第一次看到这些文件不用紧张,你先记住一件事:.vue文件是 Vue 项目的核心单元,页面最终是由一个个 .vue 组件拼装起来的。
2.3 安装依赖最容易翻车的三个点
npm install这一步看着简单,实际每一天都会有人卡住。根据这些年看到的报错,最常见的有这么几类:
镜像问题。国内直接执行npm install有时候会很慢甚至超时,解决办法是让 npm 走国内镜像:
npm config set registry https://registry.npmmirror.com设置之后再装依赖,速度会明显快一截。
权限问题。如果在安装时出现EACCES permission denied,多半是 npm 没有足够的文件写入权限。不要直接sudo npm install,那条路会让后续所有的 node_modules 文件权限都变得很怪。正解是检查你的 Node 是不是装在系统保护目录(比如/usr/local)里,如果是,请用 nvm 重装 Node,把 npm 全局目录放到用户目录下,之后再装依赖就不会有权限问题了。
node_modules 该不该发别人。这算一个常识:node_modules是本地安装依赖后生成的文件夹,动辄几百兆,里面有大量重复文件,它不应该被提交到 Git,也不应该别人要源码时直接打包发过去。正确做法是只发源码(含package.json和package-lock.json),别人拿到后执行npm install就能恢复同样的依赖环境。这个原则后面讲“项目源码怎么发给别人”时还会再提。
2.4 热更新与第一个亲手修改
Vite 开发服务器有一个很贴心但新手常忽略的功能:热更新替换(HMR)。你打开src/App.vue,把 template 里的欢迎文字随便改成“你好,Vue”,保存,浏览器里那个页面不需要你手动刷新就已经变了。
第一天你一定要亲手体验一次这个“改了代码页面自己变”的反馈,因为后面写页面时,你的工作流就是:改代码 -> 切到浏览器看效果 -> 再回来改。理论上最优先掌握的是最小 Vite 环境的知识:开发服务器是 Vite 在跑,它会把你的 .vue 文件实时编译成浏览器认识的 JavaScript,然后推送更新给页面。理解到这一层就够了,Vite 内部做了什么复杂的依赖预构建,等你有兴趣了再深入。
3. 模板语法与指令:让页面学会“说话”
3.1 插值表达式:最直观的数据展示
Vue 页面里最常见的就是双花括号插值:
<template> <p>{{ message }}</p> </template> <script setup> const message = 'Hello Vue' </script>{{ message }}会把 script 里定义的message变量的值显示到页面上。这里有个规律不用死记:script 里定义的普通变量,默认情况下只要被模板引用,就会参与响应式更新。但注意,Day 1 为了不绕晕,最好在模板里只写简单表达式,比如{{ firstName + lastName }}或者{{ count > 0 ? '有货' : '缺货' }}。如果你发现模板里写了一长串计算逻辑,那通常应该挪到方法或计算属性里,而不是堆在双花括号里。
可能会有老教程提到v-text指令也能展示文本,实际开发里几乎没人用,双花括号已经是惯例,这个知识点知道有它就行。
3.2 从属性到事件:指令与简写
光有插值只解决了“把数据显示出来”这件事。页面还要能设置元素的属性、监听用户点击。这就是指令登场的时候。
v-bind用于动态绑定 HTML 属性,比如给图片动态换地址:
<img v-bind:src="imgUrl" /> <!-- 简写 --> <img :src="imgUrl" />v-on用于监听 DOM 事件:
<button v-on:click="addItem">点我</button> <!-- 简写 --> <button @click="addItem">点我</button>Vue 里很多指令都有简写,我把最常用的几个整理成一张表,方便你直接记住:
| 指令 | 完整写法 | 简写 | 说明 |
|---|---|---|---|
| v-bind | v-bind:href | :href | 绑定属性 |
| v-on | v-on:click | @click | 绑定事件 |
| v-model | v-model="inputVal" | 无单独简写 | 双向绑定 |
| v-if / v-else / v-show | v-if="condition" | 无单独简写 | 条件渲染 |
| v-for | v-for="item in list" | 无单独简写 | 列表循环 |
上面表格里特意没写“指令简写”相关的补充,是因为这里才是真正的重点:v-bind 和 v-on 有简写,但 v-model、v-for、v-if 没有所谓更短的写法。有些新同学搜“vue指令简写”,看到网上文章才彻底明白,:src就是v-bind:src,@click就是v-on:click,仅此而已。
v-model单独拿出来说。它做的是双向绑定,也就是视图和数据“互相联动”。最典型的场景是输入框:
<input v-model.trim="inputVal" placeholder="请输入待办事项" />v-model会自动做到两件事:数据变化时,输入框的值跟着变化;用户在输入框里打字时,数据inputVal也会自动更新。.trim是修饰符,意思是在输入内容时自动去首尾空格。类似的修饰符还有.number(转数字)、.lazy(改为失焦或回车时同步,而不是每次敲键都同步)。Day 1 记住.trim就足够了,其他用到再查。
3.3 条件渲染与列表渲染
有了变量绑定、事件绑定、双向绑定,你还需要让页面能“根据数据状态决定显示什么”,以及“把一组数据铺开来展示”。
条件渲染是一组配套指令:
<p v-if="done">这条已经完成</p> <p v-else>这条还没完成</p>v-if是直接把元素加进或移出 DOM;v-show则只是用 CSS 把元素隐藏(display: none)。怎么选?一个粗糙但好用的判断是:如果状态切换很频繁,用 v-show;如果这个分支很少变成现实,用 v-if 更干净。拿电灯做类比,v-if 是直接“把灯泡摘下来”,v-show 是“把灯关上但电线还在”。第一天不用过度纠结,绝大多数情况下 v-if 就够你用了。
列表渲染用 v-for:
<li v-for="item in todoList" :key="item.id"> {{ item.text }} </li>key是一个很关键的属性。它的作用是给每个列表项一个稳定的身份标识,让 Vue 在列表变化时能准确对比新旧节点,知道哪些项需要复用、哪些需要删除。如果你不给 key,或者用数组下标当 key,在列表有增删、排序操作的场景下会出现各种诡异的状态错乱——比如你删了第 2 项,结果第 3 项输入框里残留的内容跑到第 2 项上去了。这个坑你越早养成习惯越好:v-for 永远带上 key,而且 key 不要用 index,除非你的列表是纯静态展示。
这里再补一个很多新手踩过的坑:不要在同一个元素上同时使用v-if和v-for。旧版 Vue 中 v-for 的优先级更高,同时使用很容易出现意思和你直觉不符的条件判断,即使能跑也容易引发意外。如果你的需求是“列表为空时显示空提示,有数据时渲染列表”,正确做法是分开两个元素,用v-if判断数组长度,再用另一个v-for渲染列表,或者把过滤逻辑放到 computed 里处理。
3.4 第一个综合小例子
到这里,我们第一天必学的模板语法已经全部到齐。我把它们拼成一个极简待办输入框,你可以自己在 App.vue 里改来试手:
<template> <div> <input v-model.trim="inputVal" @keyup.enter="addItem" placeholder="输入后回车" /> <ul> <li v-for="item in todoList" :key="item.id"> <input type="checkbox" v-model="item.done" /> <span>{{ item.text }}</span> </li> </ul> </div> </template> <script setup> import { ref } from 'vue' const inputVal = ref('') const todoList = ref([]) const addItem = () => { const text = inputVal.value if (!text) return todoList.value.push({ id: Date.now(), text, done: false }) inputVal.value = '' } </script>注意上面代码里出现了一个前面没详细讲的ref()。别急,这正是下一节要拆解的内容——Vue 的响应式系统,也是你理解“为什么数据变了页面自己会刷”的最后一块拼图。
4. 响应式系统:为什么数据变了页面自己会刷新
4.1 从手动操作 DOM 到声明式渲染
先回到最开始那个问题:在没有框架的年代,你要把输入框的内容同步到别的元素上,得手动监听事件再手动赋值。Vue 把这件事变成了“声明式”:你只管说“这个输入框的内容对应变量 x,这个页面的文字对应变量 message”,剩下的事情它帮你看着办。
这个“自动看着办”的系统就是响应式系统。你在 script 里用ref定义了一个变量,模板里引用了它,之后无论你在代码里什么时候修改这个变量的值,模板里所有用到它的地方都会自动更新。不需要你去写任何一行操作 DOM 的代码。
4.2 Vue 3 的 ref 与 reactive,怎么选
Vue 3 的响应式 API 有好几个,ref和reactive是最常碰到的。怎么快速理解它们的分工?
const count = ref(0) // 推荐,能放数字、字符串、数组、对象 const state = reactive({ // 推荐用于复杂对象,但直接替换会有问题 list: [], loading: false })Vue 3 内部是通过Proxy代理对象来实现拦截属性读取和修改的,所以你在写count.value = 1时,实际是触发了代理的 set 拦截逻辑,Vue 发现这个值变了,就去通知所有依赖它刷新视图的地方。
ref和reactive最直观的区别是:ref在 script 里访问值要用.value,reactive直接.属性名就能访问。不过在 Vue 3.3 之后你可能听说过ref可以做响应式解构之类的高级特性,但 Day 1 记住下面的结论就够用了:
- 基础类型的数字、字符串、布尔值,必须用
ref,只有它能处理这些类型。 - 数组、对象建议也用
ref包一层(虽然代码里写着.value有点烦,但统一心智模型最省心)。 reactive存在的意义是让你少写.value,它有隐患:直接替换整个对象时响应性会断开,比如reactive({ a: 1 })再state = { a: 2 }就会失效;解构出来的变量也会丢失响应性。- 模板里使用
ref不需要写.value,Vue 会自动给你解包,所以 script 里的一点点繁琐换来的是模板里的简洁。
第一次接触.value的人会觉得十分别扭,这完全正常。我的建议是第一天别去研究响应式原理的细节,你只需要知道:用ref定义数据,修改时记得加上.value,模板中使用时不用加。等你写顺手了,再慢慢去体会 Proxy 和 ref 解包的深水区。
4.3 v-model 背后的语法糖原理
一般来说,初学者第一眼看到 v-model 会觉得:它就是个绑定输入框的神奇属性,记住就行。但你要是想真正理解 Vue 组件的通信闭环,必须知道 v-model 不过是“值绑定 + 事件监听”的语法糖。
<input v-model="inputVal" /> <!-- 等价于 --> <input :value="inputVal" @input="inputVal = $event.target.value" />也就是说,v-model 本质上做了两件事:用:value把数据放进去,用@input监听用户输入并把输入框的最新值写回inputVal。将来你自定义一个支持 v-model 的组件时,按同样的套路实现:model-value和@update:model-value就行。
理解这一点会给很多问题带来启发。比如为什么有个modelValue这种奇怪的名字?因为它就是 v-model 默认绑定的属性名。再比如你在模板里写<input v-model="obj.text" />这种嵌套对象的绑定为什么能生效?因为 v-model 的语法糖里本来就不限制绑定到对象的哪个属性上。
4.4 计算属性:让“依赖数据的答案”自动跟新
待办页面的“还剩几项未完成”这个统计,如果你真的用模板双花括号里写复杂表达式,又会变成一坨难读的东西。更好的做法是使用计算属性computed:
import { computed, ref } from 'vue' const todoList = ref([ { id: 1, text: '学习 Vue', done: false }, { id: 2, text: '敲示例代码', done: true } ]) const remainingCount = computed(() => { return todoList.value.filter(item => !item.done).length })模板里直接用{{ remainingCount }}就行。计算属性的关键是:它会把内部依赖的响应式数据记住,只要这些数据没变,多次访问remainingCount都会直接用缓存结果,不会反复执行过滤逻辑;一旦依赖的todoList变了,它才会重新计算。对比一下,如果你写一个普通函数每次在模板里调用,页面每次重新渲染它都会重新跑一遍。这才是一个很好的启发点:凡是“依赖已有数据计算出来的新值”,都应该优先用 computed 而不是普通函数。
计算属性还有一个干净的好处:它看起来就像普通变量,模板里不需要加括号调用。这对模板的可读性提升非常明显。
5. 组件化:把整个页面拆成能复用的积木
5.1 单文件组件:一个 .vue 文件的三段式结构
前面说了,Vue 项目里页面是由 .vue 文件组合起来的。一个 .vue 文件内部通常分成三个区块:
<template>:写页面的 HTML 结构,Vue 的指令也只能在这种组件模板里用<script setup>:写逻辑,包括数据定义、事件处理、计算属性<style scoped>:写这个组件的专属样式
建议的新手拆法是把“待办输入区”拆成一个组件TodoInput,把“待办列表区”拆成另一个组件TodoList。父组件 App 只负责把数据给它们,并约定它们怎么把事件抛出去。这么做的好处是:等你要做更复杂的页面时,每个组件只需要关心自己的事情,行数少、逻辑清晰、出 bug 也好定位。
5.2 父传子:用 props 把数据递下去
父组件要把todoList传给子组件去渲染,语法很简单:
<!-- 父组件 App.vue --> <TodoList :items="todoList" />子组件里用defineProps声明接收这个属性:
<!-- TodoList.vue --> <script setup> defineProps({ items: { type: Array, required: true } }) </script> <template> <ul> <li v-for="item in items" :key="item.id">{{ item.text }}</li> </ul> </template>props 就好比父组件递给子组件一张只读的说明书:子组件能看,但不能私自修改传进来的数据。为什么不让子组件直接改?因为数据源在父组件那里,如果子组件能随便改,父组件和其他共享这份数据的组件就全乱了套。想改数据怎么办?通过事件,也就是下面要说的 emit。
5.3 子传父:用 emit 把“消息”抛上去
子组件删掉一个待办时,它自己不能直接动items,正确做法是告诉父组件“有人删除了这个 id,你看着办”。
子组件里定义事件并触发:
<!-- TodoItem.vue --> <script setup> const emit = defineEmits(['delete']) const onDelete = () => { emit('delete', item.id) } </script> <template> <li>{{ text }} <button @click="onDelete">删除</button></li> </template>父组件里监听这个事件:
<TodoItem v-for="item in items" :key="item.id" :item="item" @delete="handleDelete" />父组件收到 id,再执行真正的删除逻辑:
const handleDelete = (id) => { todoList.value = todoList.value.filter(item => item.id !== id) }emit这个名字有朋友觉得很抽象,我一般建议把它理解为“往父组件喊话”:子组件自己不处理,它只是把消息喊出去,让父组件来决策。这个通信方向在 Vue 组件体系里是最底层的规则,后续学 provide/inject、vuex、pinia 都只是在此基础上的增强。
5.4 样式冲突与 scoped:为什么明明一样的关键字却各自为政
Day 1 的组件最容易出问题的场景之一,是样式冲突。你写了一个.title红色,另一个组件里也写了一个.title蓝色,结果页面里哪个title的样式生效完全看加载次序,非常玄学。
Vue 给单文件组件提供的方案是scoped属性:
<style scoped> .title { color: red; } </style>加上 scoped 后,Vue 在编译时会自动为当前组件的元素加一个类似><style scoped> :deep(.some-outer-class .some-inner) { color: #333; } </style>
Day 1 你只要记住两条经验:写组件样式第一反应就加 scoped,别犹豫;遇到“为什么我这个组件的样式老被别人的覆盖”时,优先检查是不是没加 scoped。
6. 第一天实测会遇到的问题与后面的路线
6.1 三个常见报错的排查思路
failed to load tsconfig '@vue/tsconfig/tsconfig.web.json': tsconfig not found。这个报错一般出现在用某些带 TypeScript 的脚手架创建项目时。它的问题是项目的tsconfig.json里继承了@vue/tsconfig这个包提供的配置,但脚手架或项目里没有正确安装这个依赖,或者版本不匹配。新手最直接的解法:绕开 TypeScript,重新用纯 JavaScript 模板创建项目;如果你确实需要保留 TS,那就执行npm install -D @vue/tsconfig把缺失的依赖补上,再检查tsconfig里配置的路径是不是和这个包一致。
npm install卡住或报网络错误。除了前面提到的镜像问题,还有可能是网络代理设置导致 npm 无法出网。排查时可以看报错里有没有ETIMEDOUT、ECONNRESET之类的关键字,多半就是网络问题,切镜像后再试即可。
端口被占用。跑npm run dev时如果提示Port 5173 is already in use,Vite 默认会自动换一个端口,所以通常不用管;如果你想指定端口,改vite.config.js里的server.port配置即可。
6.2 项目源码怎么发别人:不要一上来就打包 node_modules
这个热词我特别熟悉,因为几乎每个人新手期都干过“把整个文件夹压缩发给同事”的事。500M 的压缩包里 node_modules 占了 480M,对方解压后项目照样跑不起来,因为 node_modules 里可能有本机安装的工具链差异和缓存残留。
正确做法分两种:
- 想让对方继续开发:把整个项目文件夹提交到 Git 仓库(记得写
.gitignore把 node_modules 和 dist 排掉),对方git clone后执行npm install && npm run dev就能启动。 - 只想让对方看成品:执行
npm run build,然后把生成的dist目录给他。dist里是所有源码编译压缩后的产物,可以直接部署到任意静态服务器,也可以双击本地打开查看页面的实际效果。
这两种方式和“把源码发给别人”是两件不同的事,别混淆。开发要源码,看效果要 dist。
6.3 学会 Day 1 之后,下一步怎么走
第一天的知识点已经够你写很多小工具页面了。之后再往后走,主线仍然很清晰:
第二天学 vue-router,把“页面跳转”和“导航切换”纳入体系,理解动态路由参数。
第三天学组件通信的进阶形态:插槽 slot、provide/inject,以及生命周期与网络请求。
第四天开始接触状态管理 Pinia,同时你就会发现,任何复杂的交互在掌握了组件化和响应式后都只是流程的组装。
等你把这些主线走完,再去接触实战业务会无比顺畅:比如用 HLS 流处理 m3u8 视频播放、在 Vue 项目里集成地图组件、甚至理解为什么市面上那么多低代码平台喜欢选 Vue 做基石——因为组件化、响应式、可复用的思维方式正是低代码的底座。这些听起来高大上的东西,拆开看全是你在第一天打下的基础原理。
学 Vue 头一天的体验,很多人会感觉像学任何一门新语言:语法有点绕,环境有点烦。但说句实在话,只要你把今天这些内容亲手敲过一遍、改过几个报错,后面所有的 Vue 知识都会从这个最小的闭环里生长出来。我见过太多新人在第一天纠结于“我还没记住所有 API”,其实完全没必要,API 是查出来的,真正值钱的是你脑子里的那张地图——数据驱动视图,组件拼装页面,父子之间通过 props 和 emit 说话。把这套心智模型刻进去,明天进入路由的时候,你会回来感谢今天认真搭建环境的自己。