【Web全栈进阶】Vue3起步:组件、模板语法、响应式数据

今天正式写Vue。目标是早报站首页的第一个真实组件:文章卡片------标题、摘要、链接、点赞按钮,全站复用。

🎯 本篇学会四件事 :单文件组件(SFC)怎么写、ref响应式怎么用、props怎么传参、v-for怎么渲染列表。含组件代码约60行。


📌 太长不看版(给想快速上手的你)

项目信息 一句话说明
本篇目标 写出早报站第一个Vue组件:ArticleCard
代码行数 ~60行(含注释)
依赖 无新增(脚手架已就位)
核心功能 组件 + props传参 + ref响应式 + v-for列表
跑起来的命令 npm run dev → http://localhost:5173
核心知识点 SFC、ref、defineProps、computed、v-for
做完你能得到 一个可复用、可交互、有隔离样式的文章卡片组件

一、概念复习:三句话把Vue装进脑子

在写代码前,把前端世界观翻译成Vue的三个具体机制:

# 机制 说明
① 组件 = 自包含的积木 一个.vue文件 = HTML(长得怎样)+ JS(怎么反应)+ CSS(怎么打扮)住一个房间------拆组件就是在做你之前做过的事:函数拆分,只不过拆的是 "界面函数"
② 模板 = 视图的声明 {``{ title }}就是 "这里显示title",v-for就是 "这个列表重复渲染多少次"------你声明,Vue执行
③ ref = 会通知视图的变量 普通let count = 0改了视图不知道;ref(0)包装后,count.value一变,用到它的视图自动更新------这就是 "数据是账本,视图是投影"的落地

二、第0步:清理脚手架

在上篇的daily-front项目里:

bash 复制代码
# 删掉默认的HelloWorld组件
rm src/components/HelloWorld.vue

# 清空App.vue

💡 从零开始写早报站的壳------脚手架给的默认内容都是演示,真正写项目时第一步永远是清空它们。


三、第1步:第一个组件ArticleCard

src/components/ArticleCard.vue:

vue 复制代码
<script setup>
import { computed, ref } from 'vue'

// ① props:父组件传入的参数(≈ 函数的参数,只读)
const props = defineProps({
  title: String,
  summary: String,
  url: String,
})

// ② ref:响应式状态------liked / likeCount 一变,视图自动更新
const liked = ref(false)
const likeCount = ref(0)

// ③ 事件处理:模板里的 @click 会调用它
function toggleLike() {
  liked.value = !liked.value
  likeCount.value += liked.value ? 1 : -1
}

// ④ computed:由已有数据 "派生"的新值,依赖变化自动重算
const preview = computed(() =>
  (props.summary || '').slice(0, 40) + '...')
</script>

<template>
  <article class="card">
    <h2><a :href="url" target="_blank">{{ title }}</a></h2>
    <p>{{ preview }}</p>
    <button @click="toggleLike">
      {{ liked ? '❤️ 已赞' : '🤍 点赞' }} · {{ likeCount }}
    </button>
  </article>
</template>

<style scoped>
.card { border: 1px solid #d8dee4; border-radius: 8px;
        padding: 14px 18px; margin: 12px 0; }
.card h2 { margin: 0 0 6px; font-size: 17px; }
button { cursor: pointer; border: 1px solid #1d6f9e;
         background: none; color: #1d6f9e;
         padding: 4px 12px; border-radius: 999px; }
</style>

📖 逐段拆解这个60行的文件------它同时演示了Vue的全部基础

# 概念 说明
① <script setup> 组合式API的语法糖------这里写的变量和函数,模板里直接用(setup = "准备"),不用再写一坨return
② defineProps 声明这个组件接收哪些参数。title: String意思是 "调用方必须按字符串传title"。props ≈ 函数参数 ,而且是只读的------组件不能改自己的参数
③ ref(false) 把布尔值包装成 "响应式变量"。JS里读写要.value,模板里不用------Vue自动解包
④ computed 基于props派生的摘要预览------数据变了它自动重算,不用手动维护
⑤ @click 事件绑定(v-on的简写),按钮点了调用toggleLike
⑥ <style scoped> scoped意味着这套样式只作用于本组件------组件的自我隔离,外面同名类名不影响你

四、第2步:在App.vue里使用组件

src/App.vue:

vue 复制代码
<script setup>
import ArticleCard from './components/ArticleCard.vue'

// 模拟数据:第13篇联调时换成从API拉
const articles = [
  { id: 1, title: '重构教会我的事', summary: '把歪代码拆开重装,功能不变结构变好......', url: '#' },
  { id: 2, title: '第一个爬虫抓到了什么', summary: '250部电影入库之后,我看到了榜单背后的规律......', url: '#' },
  { id: 3, title: '给项目装上AI', summary: '一次HTTP调用 + 一段好Prompt......', url: '#' },
]
</script>

<template>
  <h1>Python 早报</h1>
  <p class="subtitle">每天5分钟,掌握Python社区动态</p>
  <!-- v-for:列表渲染;:key是每个条目的身份证 -->
  <ArticleCard
    v-for="a in articles"
    :key="a.id"
    :title="a.title"
    :summary="a.summary"
    :url="a.url"
  />
</template>

📌 三个语法点

# 语法点 说明
① v-for="a in articles" 循环渲染------articles有几条,就生成几个ArticleCard
② :key="a.id" 每个列表项的身份证,Vue用它追踪 "谁是谁"------永远用稳定的id,别用下标index(第六节③)
③ :title是v-bind:title的简写 把变量值绑给prop。:title="a.title"与title="a.title"完全不同 ------后者传的是字符串字面量"a.title"

✅ 验收时刻

浏览器打开localhost:5173:

🎉 三张卡片渲染,点点赞按钮,数字+1,❤️/🤍切换------没有整页刷新,没有任何后端请求,这就是声明式渲染。


五、验收清单

bash 复制代码
1. 三张文章卡片渲染成功,样式隔离生效(scoped无污染)
2. 点击点赞 → 数字+1、图标切换,无页面刷新
3. 连点两次 → 数字回到原值(toggle逻辑正确)
4. 在articles里加第4条 → 保存即出现第四张卡(热重载 + v-for生效)
5. 故意把title拼错 → 浏览器控制台出现清晰警告(练读报错)
6. 全程无报错后提交Git
bash 复制代码
git add .
git commit -m "Vue3起步:ArticleCard组件 + 响应式点赞"

六、常见报错:这6个,Vue新手的标配(重点!)

① 页面空白,什么都没有

🔍 原因 :八成是组件没挂上------App.vue忘了import,或template里没写<ArticleCard />。

✅ 解法:三步自查------

  1. import了吗?
  2. 模板里用了吗?
  3. 组件文件路径对吗?

📌 组件不会自己出现在页面上。


② [Vue warn]: Property "articles" was accessed during render but is not defined

🔍 原因 :模板里用了articles,但script setup里没定义(或拼写不一致)。

✅ 解法 :模板引用的每个名字,都必须在script setup里存在。

📌 模板与脚本是同一份变量的两面。


③ v-for控制台警告缺key

🔍 原因 :列表渲染没写:key,或用了index当下标。

✅ 解法 :用数据的稳定id 。index当key在 "列表中间插入/删除"时会张冠李戴------后端读者可以理解为 "索引变化导致对错行"。


④ Cannot read properties of undefined (reading 'value') 或点击无反应

🔍 原因 :JS里忘了.value------liked = !liked改的是包装对象本身,不是里面的值。

✅ 解法 :script里凡是ref变量,读写一律.value;模板里不需要。

📌 记住这条分界线:JS里.value,模板里光着。


⑤ 样式写了一大堆,页面纹丝不动

🔍 原因 :<style scoped>只作用于当前组件------你写在了A组件,但类名用在B组件。

✅ 解法:

  • 全局样式(字体、背景)放App.vue的非scoped style块;
  • 组件样式各管各家。

⑥ 改完代码,页面上的点赞数归零了

🔍 原因 :不是bug------热重载/刷新后内存状态自然重置,ref是内存变量不是数据库。

✅ 解法:现阶段接受 "刷新即失忆";登录态和数据的持久化之后的(Pinia + localStorage)和(联调API)处理。


七、课后练习

# 练习 难度 提示
1 标签属性 :给ArticleCard加一个tag prop(如"AI"/"爬虫"),卡片左上角渲染一个小标签 ⭐ 复习props全流程
2 卡片跳转:把整张卡片包进链接,点击卡片跳原文 ⭐⭐ 卡片h2的a已就位,扩展到整卡
3 空摘要兜底:summary为空时显示 "(暂无摘要)" ⭐⭐ v-if / 或computed返回兜底文案------两种思路都试
4(选做) 拆SiteHeader:把标题+副标题拆成独立组件,在App里用一次 ⭐⭐ 体会 "组件即函数"的复用感

📦 配套代码

完整组件已上传Git(python_daily/,node_modules不入仓):【gitee仓库地址】

相关推荐
众链网络1 小时前
Agent 重试的工程解法:幂等、断点续跑与熔断怎么落地
java·前端·数据库·人工智能
User_芊芊君子1 小时前
JiuwenSwarm 协同智能体落地金融投研全流程:SwarmFlow 工作流编排与人机交互面板实测(A2UI v0.8 Web 通道适配)
前端·金融·人机交互
程序员大阳2 小时前
副队长CSS教程(37)–transition 过渡
前端·css·transition·过渡
ZoeLandia2 小时前
TypeScript 01:类型注解与类型推断
前端·javascript·typescript
踩蚂蚁2 小时前
从“打开灯光”看 KWS 多关键词语音控制是怎么工作的
前端
ppiero2 小时前
AI 助手聊着聊着就失忆?先分清"上下文"和"记忆"(五步装长期记忆)
前端
打呵欠的猫2 小时前
用 AI 做性能分析:一行命令找出拖慢页面的 5 个组件,优化后首屏快了 40%
前端·性能优化·ai编程
用户5080070546282 小时前
芯飞云用了两个月,说说我的真实感受
前端
Amos_Web2 小时前
Rspack 源码解析(二十一):Cacheable 与 Storage 如何持久化编译结果
前端·rust·前端框架