第1章 1.1 Vue 3 介绍与开发环境

🎯 开场 3 分钟:为什么要学 Vue 3?

想象一下这个场景:你在公司做行政,老老实实用 Excel 表格记录员工的「项目进度」。

每次改个数据,要手动找格子、改内容、核对总数。如果遇到老板说「把进度>80%的项目筛选出来,按负责人分组」,你得折腾半天,眼睛都看花了。

配图1 - 配图1

现在问题来了——有没有一种工具,能让网页像 Excel 一样,数据变了自动更新显示,而不用你手动改来改去?

答案就是 Vue 3。它帮你把「网页显示」和「数据」绑定在一起:数据变了,网页自动跟着变。你只管专心处理数据,显示的事交给 Vue。

本文学完,你将:
- 理解 Vue 3 是什么、解决什么问题
- 搭建好开发环境,跑起你的第一个 Vue 项目
- 看到一个活生生的例子,知道 Vue 是怎么干活的


🧱 基础 25 分钟:核心概念(小白视角)

什么是 Vue 3?

说白了:Vue 3 就是一个帮你「画网页」的工具。

你可以把它理解成——网页版的「数据→画面」流水线。你把数据扔进去,Vue 自动帮你渲染成好看的网页。

举个例子:你告诉 Vue「我有一个数字叫 count,值是 0」,Vue 就画出一个显示「0」的网页。你把 count 改成 1,网页自动从「0」变成「1」,不用你手动改 HTML。

为什么要用 Vue
- 传统写网页:改数据 → 手动找网页元素 → 改 innerHTML → 刷新看效果
- 用 Vue:改数据 → Vue 自动更新网页 → 完事

就像外卖软件:你在手机上改了个地址,骑手的 APP 自动收到新路线——不用你打电话通知。

搭建开发环境(Node.js + Vite)

Vue 3 的项目是用「Node.js」这个工具来跑的。把它理解成——运行 JavaScript 代码的发动机

Step 1:安装 Node.js

去 https://nodejs.org ,下载「LTS(长期支持版)」,安装完打开终端,输入:

node --version

看到一串数字(比如 v20.x.x)就说明装好了。

Step 2:用 Vite 创建 Vue 项目

Vite 是 Vue 官方推荐的「项目脚手架」,说白了就是帮你自动生成项目骨架的工具。就像装修房子,你先买个「万科精装房」而不是从打地基开始。

npm create vite@latest my-vue-app -- --template vue

解释一下这行在干嘛:
- npm create vite@latest:用 npm 运行 Vite 的创建命令
- my-vue-app:你的项目名字(可以改成你喜欢的)
- -- --template vue:告诉 Vite「我要一个 Vue 项目」

创建完,进入项目目录,安装依赖:

cd my-vue-app
npm install

依赖装好之后,启动项目:

npm run dev

你会看到类似这样的输出:

VITE v5.x.x  ready in 200 ms

➜  Local:   http://localhost:5173/
➜  Network: use --host to expose
➜  press h + enter to show help

配图2 - 配图2

恭喜你! 你的第一个 Vue 3 项目跑起来了。

打开浏览器,访问 http://localhost:5173/,你应该能看到一个带 Vue logo 的页面。

看看项目长什么样

用 VS Code 打开你的 my-vue-app 文件夹,你会看到这样的目录结构:

my-vue-app/
├── public/          # 放不会变的静态文件(比如网页图标)
├── src/             # 你的代码主要放这里 ★
│   ├── assets/      # 放图片、样式文件
│   ├── components/  # 放「组件」的地方(后面会讲)
│   ├── App.vue      # 主组件(网页的根容器)
│   └── main.js      # 入口文件(项目从这里启动)
├── index.html       # 网页的「骨架」
├── package.json     # 记录你用了哪些「工具包」
└── vite.config.js   # Vite 的配置文件

敲黑板src/App.vue 是你以后最常改的文件。先记住这个名字。

打开 App.vue,看看 Vue 的代码长啥样

<script setup>
import { ref } from 'vue'

const message = ref('Hello Vue!')
</script>

<template>
<div>
<h1>{{ message }}</h1>
</div>
</template>

这 3 段分别是什么意思

作用 类比
<script setup> 写 JavaScript 逻辑的地方 餐厅的「后厨」,决定做什么菜
<template> 写 HTML 结构的地方 餐厅的「菜单」,决定菜长什么样
(style 先忽略) 写样式的地方 餐厅的「装修」,决定好不好看

注意这行代码:

const message = ref('Hello Vue!')
  • ref() 是 Vue 提供的一个「包装盒」,它把普通数据包装成「响应式」数据
  • 响应式的意思就是:数据变了,网页自动更新
  • 'Hello Vue!' 改成 '你好 Vue!',浏览器里的文字就自动变了

🔥 实战 35 分钟:3 个递进的小项目

项目 1(5 分钟):数字计数器

目标:做一个点击按钮,数字会「+1」的小工具。

App.vue 的内容全部替换成:

<script setup>
import { ref } from 'vue'

const count = ref(0)

function addOne() {
count.value += 1
}
</script>

<template>
<div>
<h1>当前计数:{{ count }}</h1>
<button @click="addOne">点我+1</button>
</div>
</template>

保存后,浏览器里的效果
- 显示「当前计数:0」
- 点击按钮,数字变成 1、2、3……

解释
- count.valueref() 包装后的数据,访问值要用 .value
- @click="addOne" 意思是「点击这个按钮时,执行 addOne 函数」


项目 2(15 分钟):待办清单

目标:输入文字,按回车添加为待办事项,点击删除可划掉。

<script setup>
import { ref } from 'vue'

const todos = ref([
{ text: '买早餐', done: false },
{ text: '写周报', done: true }
])

const newTodo = ref('')

function addTodo() {
if (newTodo.value.trim() === '') return
todos.value.push({ text: newTodo.value, done: false })
newTodo.value = ''
}

function toggleDone(index) {
todos.value[index].done = !todos.value[index].done
}

function deleteTodo(index) {
todos.value.splice(index, 1)
}
</script>

<template>
<div>
<h1>我的待办清单</h1>
<input 
  v-model="newTodo" 
  @keyup.enter="addTodo" 
  placeholder="输入待办事项,按回车添加"
/>
<ul>
  <li v-for="(todo, index) in todos" :key="index">
    <span 
      :class="{ done: todo.done }"
      @click="toggleDone(index)"
    >
      {{ todo.text }}
    </span>
    <button @click="deleteTodo(index)">删除</button>
  </li>
</ul>
<p>共 {{ todos.length }} 项,已完成 {{ todos.filter(t => t.done).length }} 项</p>
</div>
</template>

<style scoped>
.done {
text-decoration: line-through;
color: gray;
}
li {
list-style: none;
margin: 8px 0;
}
</style>

效果
- 输入「开会」,按回车,列表多了一项「开会」
- 点击「开会」,文字变灰色加删除线(表示完成)
- 点击「删除」,这一项消失
- 底部显示「共 3 项,已完成 1 项」

几个新知识点

语法 作用
v-model="newTodo" 把输入框和 newTodo 变量「双向绑定」,输入框打字,变量跟着变
v-for="..." 循环渲染列表,就像 Python 里的 for 循环
:class="{ done: todo.done }" 条件class,如果 todo.done 是 true,就加上 done 这个样式

项目 3(15 分钟):数据过滤器

目标:一个输入框,输入名字实时筛选下面的列表。

这个项目把「输入」和「列表显示」结合起来,模拟真实的数据处理场景。

<script setup>
import { ref, computed } from 'vue'

const employees = ref([
{ name: '张三', department: '技术部', salary: 12000 },
{ name: '李四', department: '市场部', salary: 10000 },
{ name: '王五', department: '技术部', salary: 15000 },
{ name: '赵六', department: '人事部', salary: 9000 }
])

const filterText = ref('')

const filteredEmployees = computed(() => {
if (!filterText.value) return employees.value
return employees.value.filter(e => 
e.name.includes(filterText.value) || 
e.department.includes(filterText.value)
)
})

const totalSalary = computed(() => {
return filteredEmployees.value.reduce((sum, e) => sum + e.salary, 0)
})
</script>

<template>
<div>
<h1>员工工资表</h1>
<input 
  v-model="filterText" 
  placeholder="输入姓名或部门筛选"
/>
<table border="1" style="margin-top: 16px; border-collapse: collapse;">
  <thead>
    <tr>
      <th>姓名</th>
      <th>部门</th>
      <th>工资</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="emp in filteredEmployees" :key="emp.name">
      <td>{{ emp.name }}</td>
      <td>{{ emp.department }}</td>
      <td>¥{{ emp.salary.toLocaleString() }}</td>
    </tr>
  </tbody>
</table>
<p>筛选后共 {{ filteredEmployees.length }} 人,合计工资 ¥{{ totalSalary.toLocaleString() }}</p>
</div>
</template>

效果
- 输入「技术」,列表只显示张三和王五,合计工资自动更新
- 输入「15000」,没匹配结果,显示「共 0 人」
- 清空输入框,恢复显示全部

新知识点

语法 作用
computed() 计算属性,依赖的数据变了自动重新计算(类似 Excel 公式)
toLocaleString() 把数字格式化成「1,200」这种带千分位的形式

💪 进阶 20 分钟:常见坑 + 调试技巧

坑 1:ref 里的值不是直接读写的

// ❌ 错误:这样改 count,网页不会更新
count = 10

// ✅ 正确:要加 .value
count.value = 10

类比ref() 像一个有「透明窗口」的保险箱,你得透过窗口(.value)才能动里面的东西。


坑 2:v-model 和输入框的类型

<!-- ❌ 如果 age 是数字,输入法打出的中文可能有问题 -->
<input v-model="age" />

<!-- ✅ 加 .number 修饰符,Vue 会自动转数字 -->
<input v-model.number="age" />

坑 3:v-for 忘了加 :key

<!-- ❌ 没加 key,Vue 会报警告,列表可能渲染出错 -->
<li v-for="todo in todos">{{ todo.text }}</li>

<!-- ✅ 加唯一的 key,Vue 知道每个元素是谁 -->
<li v-for="(todo, index) in todos" :key="index">{{ todo.text }}</li>

坑 4:模板里不要写复杂逻辑

<!-- ❌ 模板里写三元表达式嵌套,可读性差 -->
<span>{{ a ? (b ? '对' : '错') : '都不是' }}</span>

<!-- ✅ 放到 computed 里,模板只负责显示 -->
<span>{{ statusText }}</span>

原则:模板是「展示」的地方,逻辑放到 <script setup> 里。


坑 5:数组和对象的修改要小心

// ❌ 这种情况不触发响应式更新
const list = ref([1, 2, 3])
list.value[0] = 100  // ❌ 不会更新!

// ✅ 用 splice 或者整个替换
list.value.splice(0, 1, 100)  // ✅ 触发更新
// 或者
list.value = [...list.value]  // 触发更新(创建新数组)

调试技巧:console.log 大法

Vue 3 的 ref 对象可以直接打印看内容:

const count = ref(0)
console.log(count)        // 看到的是 Ref 对象
console.log(count.value)  // 看到的是 0

toggleDone 函数里加个 console.log,可以看到点击时数据怎么变的:

function toggleDone(index) {
console.log('点击了第', index, '项', '之前的状态:', todos.value[index].done)
todos.value[index].done = !todos.value[index].done
console.log('之后的状态:', todos.value[index].done)
}

✏️ 练习题

练习 1(1 分钟):改改计数器

  • 输入:把项目 1 的 count 初始值改成 100
  • 预期输出:页面显示「当前计数:100」,点一下按钮变成 101
  • 提示:找到 ref(0),改掉那个 0 就行

练习 2(2 分钟):计数器加个「减 1」按钮

  • 输入:在项目 1 基础上,加一个「点我-1」按钮
  • 预期输出:两个按钮都能正常工作
  • 提示:写一个 minusOne() 函数,count.value -= 1

练习 3(3 分钟):待办清单加个「清空已完成」

  • 输入:在项目 2 基础上,加一个按钮,点击删除所有 done: true 的项
  • 预期输出:点击后,已完成的事项全部消失
  • 提示:用 todos.value.filter(t => !t.done) 过滤出未完成的,赋值回 todos.value

练习 4(3 分钟):员工表按工资排序

  • 输入:在项目 3 基础上,加一个按钮,点击按工资从高到低排序
  • 预期输出:点击后,表格里的顺序变了
  • 提示:用 sort((a, b) => b.salary - a.salary)filteredEmployees 排序

练习 5(5 分钟):为什么没更新?

看下面这段代码,点击按钮后数字不会变,为什么?

<script setup>
const count = 0  // 没有 ref 包装!
function addOne() {
count += 1
}
</script>

<template>
<div>
<h1>{{ count }}</h1>
<button @click="addOne">点我+1</button>
</div>
</template>
  • 预期输出:解释为什么网页不更新,以及怎么修
  • 提示:Vue 的响应式系统需要数据被 ref() 包装才能追踪变化

作业:做一个「个人开支记录器」

需求描述:做一个可以记录日常开支的小工具,输入金额和说明,保存后显示列表,底部显示总支出。

功能点
1. 输入「金额」和「说明」,点击「添加」保存到列表
2. 显示所有开支记录,每条可以删除
3. 底部显示「总支出:¥XXX」

加分项
1. 显示每条记录的时间(用 new Date().toLocaleString()
2. 输入验证:金额必须是正数,说明不能为空

验收标准
- 能跑起来,npm run dev 不报错
- 添加记录后列表显示正确
- 删除记录后列表更新
- 总支出是所有记录金额之和


📚 总结 + 资源

本文学了 3 件事
1. Vue 3 是帮你「数据→网页」自动绑定的工具
2. 用 Vite 5 分钟能搭好一个 Vue 项目
3. ref() 包装数据让它「响应式」,v-model/v-for/v-bind 是最常用的指令

延伸学习资源

资源 链接 适合谁
Vue 官方文档 https://vuejs.org/tutorial/ 喜欢看官方教程的人
《Vue 3设计与实现》 各大电商平台有售 想深入理解原理的人
B站「技术浩」Vue 合集 搜索关键词 喜欢看视频学习的

互动钩子:你在工作中有没有遇到过「改数据要手动更新网页」的场景?当时是怎么解决的?评论区聊聊,选 3 个典型问题下期集中回答!


下期预告:下一章我们要聊一个很实际的问题——{{ message }}v-ifv-for 这些「模板语法」到底怎么用?什么时候该用哪个?很多新手栽在这上面……

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。