L07.5 Vue 基础知识补丁
学习目标
学完这一课,你能够:
- [ ] 说出Vue是什么,用来做什么
- [ ] 解释什么是"组件"
- [ ] 理解
ref、onMounted的作用 - [ ] 看懂简单的Vue代码
- [ ] 用AI生成Vue组件
学习进度
阶段2:开发实现
├── L07 项目搭建 ✅
├── L07.5 Vue基础 ← 你在这里
├── L08 用户认证
└── ...这节课是在 L07 和 L08 之间的"加餐",帮你理解 Vue 的基本概念。 如果你之前没接触过 Vue,或者感觉有点懵,先看这个!
一、为什么需要 Vue?
1.1 先看传统网页怎么做
假设你要做一个计数器:点击按钮,数字加1。
用传统 HTML + JavaScript:
<button onclick="add()">点击了 <span id="count">0</span> 次</button>
<script>
let count = 0;
function add() {
count = count + 1;
document.getElementById('count').innerText = count;
}
</script>问题来了:
- 你要手动找到那个
span元素 - 你要手动修改它的内容
- 如果页面复杂,这种"找元素、改元素"的代码会非常多,乱成一团
1.2 Vue 的解决方案:数据绑定
Vue 说:你别管页面怎么更新,你只管改数据,页面自动变。
<template>
<button @click="count++">点击了 {{ count }} 次</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>看,没有 getElementById,没有 innerText。 你改了 count,页面自动更新。这就是 Vue 的魔法。
1.3 乐高积木的类比
Vue 的另一个核心思想是组件化。
想象你在搭乐高:
- 你不会每次都从头捏一个轮子
- 你有"轮子组件"、"窗户组件"、"门组件"
- 把这些组件拼起来,就是一辆车
Vue 组件就是乐高积木:
Header组件:页面顶部的导航栏ItemCard组件:展示一个商品的卡片Footer组件:页面底部的信息
拼起来就是一个完整的页面。
二、Vue 组件的三个部分
一个 Vue 组件文件(.vue 文件)通常有三块:
<template>
<!-- 这里写 HTML:页面长什么样 -->
</template>
<script setup>
// 这里写 JavaScript:页面能做什么
</script>
<style scoped>
/* 这里写 CSS:页面好不好看 */
</style>2.1 模板(Template):长什么样
就是 HTML,但加了点"魔法语法":
<template>
<div class="counter">
<h1>计数器</h1>
<p>当前数字:{{ count }}</p>
<button @click="add">加 1</button>
</div>
</template>{{ count }}:显示count变量的值@click="add":点击时执行add函数
2.2 脚本(Script):能做什么
就是 JavaScript,用 Vue 3 的"组合式 API":
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add() {
count.value = count.value + 1;
}
</script>ref(0):创建一个"响应式"变量,初始值是 0count.value:读取或修改这个变量的值- 为什么是
.value?因为ref把数据包了一层,这样 Vue 才能监听变化
2.3 样式(Style):好不好看
就是 CSS,加了 scoped 表示"只作用于这个组件":
<style scoped>
.counter {
text-align: center;
padding: 20px;
}
button {
background: #42b983;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
}
</style>三、完整的计数器例子
把上面三块拼起来:
<template>
<div class="counter">
<h1>计数器</h1>
<p>当前数字:{{ count }}</p>
<button @click="add">加 1</button>
<button @click="reset">重置</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function add() {
count.value = count.value + 1;
}
function reset() {
count.value = 0;
}
</script>
<style scoped>
.counter {
text-align: center;
padding: 20px;
}
button {
margin: 5px;
padding: 10px 20px;
background: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #3aa876;
}
</style>逐行解释:
| 行号 | 代码 | 解释 |
|---|---|---|
| 2 | <div class="counter"> | 一个容器,用来包住所有内容 |
| 4 | {{ count }} | 显示 count 变量的值 |
| 5 | @click="add" | 点击按钮时调用 add 函数 |
| 11 | import { ref } from 'vue' | 从 Vue 引入 ref 功能 |
| 13 | const count = ref(0) | 创建一个响应式变量,初始值是 0 |
| 15-17 | function add() {...} | 定义一个函数,让 count 加 1 |
| 19-21 | function reset() {...} | 定义一个函数,让 count 变回 0 |
| 25 | <style scoped> | 样式只作用于这个组件 |
四、Vue 3 常用语法速查
4.1 ref:一个会变的盒子
import { ref } from 'vue';
const name = ref('张三'); // 字符串
const age = ref(18); // 数字
const hobbies = ref(['游泳', '读书']); // 数组
// 读取值
console.log(name.value); // '张三'
// 修改值
name.value = '李四';
age.value = 19;
hobbies.value.push('游戏');类比:ref 就像一个透明的盒子,里面装着你的数据。
- 你要通过
.value才能拿到里面的东西 - 当你换掉里面的东西,Vue 能立刻察觉并更新页面
4.2 onMounted:页面加载完做什么
<script setup>
import { ref, onMounted } from 'vue';
const message = ref('加载中...');
onMounted(() => {
// 这里的代码会在页面显示之后执行
setTimeout(() => {
message.value = '加载完成!';
}, 1000);
});
</script>
<template>
<p>{{ message }}</p>
</template>类比:就像你装修房子,onMounted 是"装修完成后"你要做的事, 比如"请朋友来吃饭"。
4.3 v-if:条件显示
<template>
<div v-if="isLoggedIn">
欢迎回来!
</div>
<div v-else>
请先登录
</div>
</template>
<script setup>
import { ref } from 'vue';
const isLoggedIn = ref(false);
</script>v-if="条件":条件为真时显示v-else:否则显示
4.4 v-for:循环显示
<template>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }} - ¥{{ item.price }}
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue';
const items = ref([
{ id: 1, name: '二手自行车', price: 100 },
{ id: 2, name: '考研资料', price: 50 },
{ id: 3, name: '小台灯', price: 25 },
]);
</script>v-for="item in items":遍历 items 数组:key="item.id":给每个元素一个唯一标识(Vue 要求的)
类比:就像老师点名,按名单一个一个念。
4.5 @click:点击事件
<template>
<button @click="sayHello">点我</button>
<button @click="count++">加1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function sayHello() {
alert('你好!');
}
</script>@click="函数名":点击时调用函数@click="表达式":点击时执行表达式(比如count++)
4.6 v-model:表单绑定
<template>
<input v-model="username" placeholder="请输入用户名">
<p>你输入的是:{{ username }}</p>
</template>
<script setup>
import { ref } from 'vue';
const username = ref('');
</script>v-model 的魔法:
- 你在输入框里打字,
username自动更新 - 你修改
username,输入框里显示的内容也自动变
类比:就像对讲机,两边同步。
五、组件之间的关系
5.1 组件就是乐高积木
页面(App.vue)
├── 头部(Header.vue)──── 导航栏
├── 内容区
│ ├── 商品卡片(ItemCard.vue)── 第一个商品
│ ├── 商品卡片(ItemCard.vue)── 第二个商品
│ └── 商品卡片(ItemCard.vue)── 第三个商品
└── 底部(Footer.vue)──── 版权信息5.2 父子组件通信
父传子(Props):父组件给子组件传数据
<!-- 父组件 App.vue -->
<template>
<ItemCard title="二手自行车" price="100" />
</template>
<!-- 子组件 ItemCard.vue -->
<template>
<div class="card">
<h3>{{ title }}</h3>
<p>¥{{ price }}</p>
</div>
</template>
<script setup>
defineProps({
title: String,
price: String,
});
</script>类比:父母给孩子零花钱,孩子接收并使用。
子传父(Emit):子组件通知父组件
<!-- 子组件 ItemCard.vue -->
<template>
<button @click="handleClick">加入收藏</button>
</template>
<script setup>
const emit = defineEmits(['favorite']);
function handleClick() {
emit('favorite', '二手自行车'); // 通知父组件
}
</script>
<!-- 父组件 App.vue -->
<template>
<ItemCard @favorite="onFavorite" />
</template>
<script setup>
function onFavorite(itemName) {
console.log('用户收藏了:', itemName);
}
</script>类比:孩子喊"我饿了",父母听到后做饭。
六、练习任务
任务:做一个简单的计数器
要求:
- 显示当前数字
- 有"加1"和"减1"两个按钮
- 数字不能小于0
- 有一个"重置"按钮
参考代码
创建文件 project/frontend/src/components/Counter.vue:
<template>
<div class="counter">
<h2>计数器练习</h2>
<p class="number">{{ count }}</p>
<div class="buttons">
<button @click="decrease" :disabled="count === 0">减 1</button>
<button @click="reset">重置</button>
<button @click="increase">加 1</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function increase() {
count.value++;
}
function decrease() {
if (count.value > 0) {
count.value--;
}
}
function reset() {
count.value = 0;
}
</script>
<style scoped>
.counter {
text-align: center;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
max-width: 300px;
margin: 20px auto;
}
.number {
font-size: 48px;
font-weight: bold;
color: #42b983;
margin: 20px 0;
}
.buttons {
display: flex;
justify-content: center;
gap: 10px;
}
button {
padding: 10px 20px;
font-size: 16px;
border: none;
border-radius: 4px;
cursor: pointer;
background: #42b983;
color: white;
}
button:hover {
background: #3aa876;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
</style>运行方式
- 在
App.vue中引入并使用:
<template>
<Counter />
</template>
<script setup>
import Counter from './components/Counter.vue';
</script>- 启动开发服务器:
cd project/frontend
npm run dev- 打开浏览器访问
http://localhost:5173
进阶挑战
如果你觉得太简单,试试这些:
- 增加输入框:用户可以输入任意数字,然后在此基础上加减
- 增加步长:用户可以选择每次加减 1、5、10
- 添加动画:数字变化时有过渡效果
七、常见问题
Q1: 为什么 ref 要用 .value?
因为 JavaScript 的基础类型(数字、字符串)是"按值传递"的, Vue 没办法直接监听它们的变化。所以 Vue 把它包在一个对象里, 这样就能监听了。
你可以把 ref 理解为一个盒子,.value 才是里面的东西。
Q2: template 里为什么不用 .value?
Vue 在模板里会自动"解包" ref,所以你直接写 {{ count }} 就行, 不用写 {{ count.value }}。
但在 <script> 里,你必须写 .value。
Q3: v-if 和 v-show 有什么区别?
v-if:条件为假时,元素根本不会渲染到页面上v-show:元素始终存在,只是用 CSS 隐藏了
简单记忆:频繁切换用 v-show,不怎么切换用 v-if。
Q4: 为什么 v-for 要有 key?
Vue 用 key 来追踪每个元素的身份。 如果 key 不变,Vue 会复用这个元素(提高性能)。 如果 key 变了,Vue 会重新创建。
永远不要用 index 作为 key(除非列表永远不会变), 因为 index 会变,会导致奇怪的 bug。
小结
这节课我们学了:
| 概念 | 作用 | 类比 |
|---|---|---|
| ref | 创建响应式数据 | 一个会变的盒子 |
| template | 写页面结构 | 房子的设计图 |
| script | 写逻辑代码 | 房子的功能 |
| style | 写样式 | 房子的装修 |
| v-if | 条件显示 | 满足条件才开门 |
| v-for | 循环显示 | 点名,一个一个来 |
| @click | 点击事件 | 按门铃 |
| v-model | 双向绑定 | 对讲机 |
| props | 父传子 | 父母给零花钱 |
| emit | 子传父 | 孩子喊"饿了" |
下一节 L08,我们会用这些知识来实现用户登录功能。 准备好了吗?
✅ 学习检验
你能解释这些概念吗?
试着用自己的话回答(不要背定义):
- 组件是什么? 能用"乐高积木"的类比说清楚吗?
- 响应式是什么? 和Excel公式有什么相似之处?
- ref 为什么要加 .value? 模板里为什么不用加?
你能教给别人吗?
用1分钟向你的朋友解释:
- Vue是做什么的?
- 为什么用Vue比直接写HTML方便?
自测题
- 下面的代码会显示什么?
<template>
<p>{{ message }}</p>
</template>
<script setup>
const message = 'Hello'
</script>- 点击按钮后,页面上的数字会变成几?
<template>
<button @click="count++">点击</button>
<p>点击次数: {{ count }}</p>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>查看答案
- 显示:Hello
- 点击后显示:点击次数: 1
📚 扩展资源
官方文档
- Vue 3 官方文档(中文) - 关键词:组件、响应式、组合式API
- Vue 3 教程 - 官方互动教程,推荐边学边练
推荐阅读
- Vue 3 入门指南 - 官方入门文档
- 组合式API常见问答 - 理解组合式API
视频教程
- B站搜索"Vue3入门" - 选择播放量高的教程
本课关键词
Vue 组件 响应式 ref reactive onMounted v-if v-for v-model props emit