Skip to content

L07.5 Vue 基础知识补丁

学习目标

学完这一课,你能够:

  • [ ] 说出Vue是什么,用来做什么
  • [ ] 解释什么是"组件"
  • [ ] 理解refonMounted的作用
  • [ ] 看懂简单的Vue代码
  • [ ] 用AI生成Vue组件

学习进度

阶段2:开发实现
├── L07 项目搭建 ✅
├── L07.5 Vue基础 ← 你在这里
├── L08 用户认证
└── ...

这节课是在 L07 和 L08 之间的"加餐",帮你理解 Vue 的基本概念。 如果你之前没接触过 Vue,或者感觉有点懵,先看这个!


一、为什么需要 Vue?

1.1 先看传统网页怎么做

假设你要做一个计数器:点击按钮,数字加1。

用传统 HTML + JavaScript:

html
<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 说:你别管页面怎么更新,你只管改数据,页面自动变。

html
<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 文件)通常有三块:

vue
<template>
  <!-- 这里写 HTML:页面长什么样 -->
</template>

<script setup>
  // 这里写 JavaScript:页面能做什么
</script>

<style scoped>
  /* 这里写 CSS:页面好不好看 */
</style>

2.1 模板(Template):长什么样

就是 HTML,但加了点"魔法语法":

html
<template>
  <div class="counter">
    <h1>计数器</h1>
    <p>当前数字:{{ count }}</p>
    <button @click="add">加 1</button>
  </div>
</template>
  • &#123;&#123; count &#125;&#125;:显示 count 变量的值
  • @click="add":点击时执行 add 函数

2.2 脚本(Script):能做什么

就是 JavaScript,用 Vue 3 的"组合式 API":

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

const count = ref(0);

function add() {
  count.value = count.value + 1;
}
</script>
  • ref(0):创建一个"响应式"变量,初始值是 0
  • count.value:读取或修改这个变量的值
  • 为什么是 .value?因为 ref 把数据包了一层,这样 Vue 才能监听变化

2.3 样式(Style):好不好看

就是 CSS,加了 scoped 表示"只作用于这个组件":

vue
<style scoped>
.counter {
  text-align: center;
  padding: 20px;
}
button {
  background: #42b983;
  color: white;
  border: none;
  padding: 10px 20px;
  cursor: pointer;
}
</style>

三、完整的计数器例子

把上面三块拼起来:

html
<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&#123;&#123; count &#125;&#125;显示 count 变量的值
5@click="add"点击按钮时调用 add 函数
11import { ref } from 'vue'从 Vue 引入 ref 功能
13const count = ref(0)创建一个响应式变量,初始值是 0
15-17function add() {...}定义一个函数,让 count 加 1
19-21function reset() {...}定义一个函数,让 count 变回 0
25<style scoped>样式只作用于这个组件

四、Vue 3 常用语法速查

4.1 ref:一个会变的盒子

javascript
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:页面加载完做什么

html
<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:条件显示

vue
<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:循环显示

html
<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:点击事件

vue
<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:表单绑定

html
<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):父组件给子组件传数据

html
<!-- 父组件 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):子组件通知父组件

vue
<!-- 子组件 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. 显示当前数字
  2. 有"加1"和"减1"两个按钮
  3. 数字不能小于0
  4. 有一个"重置"按钮

参考代码

创建文件 project/frontend/src/components/Counter.vue

html
<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>

运行方式

  1. App.vue 中引入并使用:
vue
<template>
  <Counter />
</template>

<script setup>
import Counter from './components/Counter.vue';
</script>
  1. 启动开发服务器:
bash
cd project/frontend
npm run dev
  1. 打开浏览器访问 http://localhost:5173

进阶挑战

如果你觉得太简单,试试这些:

  1. 增加输入框:用户可以输入任意数字,然后在此基础上加减
  2. 增加步长:用户可以选择每次加减 1、5、10
  3. 添加动画:数字变化时有过渡效果

七、常见问题

Q1: 为什么 ref 要用 .value?

因为 JavaScript 的基础类型(数字、字符串)是"按值传递"的, Vue 没办法直接监听它们的变化。所以 Vue 把它包在一个对象里, 这样就能监听了。

你可以把 ref 理解为一个盒子,.value 才是里面的东西。

Q2: template 里为什么不用 .value?

Vue 在模板里会自动"解包" ref,所以你直接写 &#123;&#123; count &#125;&#125; 就行, 不用写 &#123;&#123; count.value &#125;&#125;

但在 <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,我们会用这些知识来实现用户登录功能。 准备好了吗?


✅ 学习检验

你能解释这些概念吗?

试着用自己的话回答(不要背定义):

  1. 组件是什么? 能用"乐高积木"的类比说清楚吗?
  2. 响应式是什么? 和Excel公式有什么相似之处?
  3. ref 为什么要加 .value? 模板里为什么不用加?

你能教给别人吗?

用1分钟向你的朋友解释:

  • Vue是做什么的?
  • 为什么用Vue比直接写HTML方便?

自测题

  1. 下面的代码会显示什么?
html
<template>
  <p>{{ message }}</p>
</template>
<script setup>
const message = 'Hello'
</script>
  1. 点击按钮后,页面上的数字会变成几?
html
<template>
  <button @click="count++">点击</button>
  <p>点击次数: {{ count }}</p>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
查看答案
  1. 显示:Hello
  2. 点击后显示:点击次数: 1

📚 扩展资源

官方文档

推荐阅读

视频教程

  • B站搜索"Vue3入门" - 选择播放量高的教程

本课关键词

Vue 组件 响应式 ref reactive onMounted v-if v-for v-model props emit


上一篇L07 项目搭建
下一篇L08 用户认证

基于 CC BY-NC-SA 4.0 发布