Vue 第1课:把接口数据渲染成页面
课程目标:用 Vue 把已经跑通的 Spring Boot 接口变成人能看的页面
预计时间:45 分钟
前置条件:第1课的
预计时间:45 分钟
前置条件:第1课的
/hello/{name} 与 /about 已能跑
回头看第1课
还记得第1课那几行 @RestController 吗?接口是有了,但浏览器打开的是一串 JSON,只有开发者看得懂。
比如访问 http://localhost:8080/about,你看到的是:
{"course":"Spring Boot","lesson":1,"author":"MiMo"}
这串数据对机器很友好,但对人来说不够直观。今天我们就用 Vue 把它变成一个漂亮的页面。
本课阅读方式:
正文里带彩色虚线下划线的名词,鼠标放上去就会弹出一个小窗,
里面是三段式:① 官方定义(正式术语 + 英文全称)→
② 一句话大白话 → ③ 生活类比;
带用法的名词(比如各种
每个名词只在第一次出现时带下划线,之后再出现只保留颜色,不再重复弹窗。 全部 69 个名词都记录在 名词速查笔记 GLOSSARY.md(带目录,可搜索)。 答疑和笔记都收在 DSH 笔记文档页。
@ 注解)还会多一段
④ 规范写法——可直接照抄的最小代码示例。
比如把鼠标放到 响应式 上试试。每个名词只在第一次出现时带下划线,之后再出现只保留颜色,不再重复弹窗。 全部 69 个名词都记录在 名词速查笔记 GLOSSARY.md(带目录,可搜索)。 答疑和笔记都收在 DSH 笔记文档页。
从 JSON 到页面:Vue 数据渲染之旅
① 为什么需要模板?
想象一下:你要在页面上显示 "课程:Spring Boot,第1课,作者:MiMo"。
如果用原生 JavaScript,你得这样写:
document.getElementById('course').textContent = data.course;
document.getElementById('lesson').textContent = data.lesson;
document.getElementById('author').textContent = data.author;
但用 Vue 的 模板,你只需要:
<div>课程:{{ course }},第{{ lesson }}课,作者:{{ author }}</div>
模板就像一个填空题:数据变了,页面自动更新。
静态 HTML 页面→引入 Vue 框架→创建应用实例→绑定数据到模板→页面动态更新
② 最小可用三件套
不引入构建工具链,我们用最简单的方式:
index.html- 页面入口app.js- Vue 应用api.js- 数据获取
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Vue 数据渲染</title>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<p>课程:{{ course }}</p>
</div>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
}
}
</script>
<!-- 实际项目中这里引用你的 app.js -->
<script type="module" src="app.js"></script>
</body>
</html>
app.js
import { createApp } from 'vue';
import { fetchAbout } from './api.js';
const app = createApp({
data() {
return {
title: 'Vue 数据渲染',
course: '',
lesson: 0,
author: ''
};
},
async mounted() {
const data = await fetchAbout();
this.course = data.course;
this.lesson = data.lesson;
this.author = data.author;
}
});
app.mount('#app');
api.js
export async function fetchAbout() {
const response = await fetch('http://localhost:8080/about');
return await response.json();
}
验证:打开 index.html,看到 "Vue 数据渲染" 和课程信息。
③ 响应式:数据变,页面变
Vue 的核心是 响应式系统。用 ref() 创建响应式数据:
import { ref } from 'vue';
const message = ref('Hello Vue');
// 模板中:{{ message }}
// 改值:message.value = 'Hi Vue';
// 页面自动更新!
试试:在输入框里打字,页面上的字当场跟着变。
<input v-model="message" />
<p>你输入了:{{ message }}</p>
这就是 v-model 的魔力:输入框和数据双向绑定。
④ 列表与条件:渲染数组
如果接口返回的是数组,用 v-for 渲染:
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
用 v-if 做三态(加载中 / 有数据 / 出错):
<div v-if="loading">加载中...</div>
<div v-else-if="error">出错了:{{ error }}</div>
<div v-else>{{ data }}</div>
加载中→数据加载成功→加载失败
⑤ 取数据:fetch + async/await
从 Spring Boot 接口获取数据:
async function loadData() {
try {
const response = await fetch('http://localhost:8080/about');
const data = await response.json();
// 把数据交给 ref
course.value = data.course;
lesson.value = data.lesson;
author.value = data.author;
} catch (err) {
error.value = err.message;
}
}
为什么页面会闪一下?
因为 await 前页面是空的,await 后数据才来。这就是为什么我们要做三态:先显示"加载中",数据来了再显示内容。
T1浏览器请求页面T2Vue 应用初始化T3fetch 调用 Spring Boot 接口T4返回 JSON 数据T5数据渲染到页面
⑥ 跨域这道墙
打开浏览器控制台,看到这个错误了吗?
Access to fetch at 'http://localhost:8080/about'
from origin 'null' has been blocked by CORS policy
浏览器为了安全,不允许页面请求不同源的接口。
解决方法:在 Spring Boot 控制器上加 @CrossOrigin
@RestController
@CrossOrigin // 加这一行
public class HelloController {
// ...
}
重启 Spring Boot,刷新页面,控制台不再报错。
⑦ 常见错误对照表
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| CORS 报错 | 没加 @CrossOrigin |
在控制器上加注解 |
| 404 Not Found | 端口写错(8080 vs 3000) | 检查 fetch 的 URL |
| undefined | 字段名拼错 | 对比 JSON 和模板 |
| 页面空白 | 忘了 mount('#app') |
检查 app.js 最后一行 |
⑧ 小测验
Vue 的响应式系统用什么创建?
- var
- let
- ref()
- const
解决跨域问题要加什么注解?
- @RestController
- @CrossOrigin
- @GetMapping
- @RequestBody
全部 69 个名词(含前面课程内容)都在
GLOSSARY.md 里,带目录表格,可直接搜索。
推荐阅读(按优先级)
课后挑战(做完再往下学)
- 最小可用三件套
做:创建index.html+app.js+api.js,用 importmap 引入 Vue,createApp 挂在#app上
验收:打开页面看到一句话(可以是硬编码的"Hello Vue") - 渲染 /about 接口
做:调用第1课的/about接口,把course/lesson/author三个字段显示在页面上
验收:页面显示 "课程:Spring Boot,第1课,作者:MiMo" - 响应式输入框
做:用 ref() 存输入值,v-model 绑输入框,页面实时显示输入内容
验收:目视确认:输入框打字时页面同步变化,控制台无报错 - 拆掉跨域
做:在 Spring Boot 控制器上加@CrossOrigin,重启后刷新页面
验收:目视确认:浏览器控制台里没有 "blocked by CORS policy" 错误