前面我们学习了 Vue 的响应式数据、ref、Todos 任务清单,但这些都是在单文件里完成的。

今天我们来做一个真正的 Vue 项目——一个拥有多页面、路由导航、组件化架构的现代前端应用。
这个项目虽然小,但它麻雀虽小五脏俱全,涵盖了 Vue 3 项目开发的核心骨架:
完整项目链接:gitee.com/hong-strong…
复制代码all-vue/
├── public/
│ └── favicon.svg
├── src/
│ ├── router/
│ │ └── index.js # 路由配置
│ ├── views/
│ │ ├── Home.vue # 首页组件
│ │ └── About.vue # 关于页组件
│ ├── App.vue # 根组件
│ ├── main.js # 入口文件
│ └── style.css # 全局样式
├── index.html # HTML 入口
├── package.json
└── vite.config.js # Vite 配置
| 文件/目录 | 职责 | 类比 |
|---|---|---|
index.html | 整个应用的 HTML 入口 | 房子的地基 |
main.js | JS 入口,创建 Vue 应用实例 | 房子的总开关 |
App.vue | 根组件,包裹所有页面 | 房子的框架 |
router/index.js | 路由配置,决定 URL 对应哪个页面 | 房子的门牌号 |
views/*.vue | 具体的页面组件 | 房子的各个房间 |
style.css | 全局样式 | 房子的装修风格 |
vite.config.js | 构建工具配置 | 施工图纸 |
复制代码<!-- index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>all-vue</title>
</head>
<body>
<!-- 组件的挂载点 -->
<div id="app"></div>
<!-- vue 基于最新的 ESM,type="module" -->
<script type="module" src="/src/main.js"></script>
</body>
</html>
逐行解析:
复制代码<div id="app"></div>
复制代码<script type="module" src="/src/main.js"></script>
type="module" 表示使用 ESM(ES Modules) 规范import/export 复制代码// main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router';createApp(App)
.use(router) // 启用路由
.mount('#app') // 挂载到 #app
逐行解析:
复制代码import { createApp } from 'vue'
vue 包中引入 createApp 函数createApp 创建应用实例(Vue 2 是 new Vue()) 复制代码import './style.css'
复制代码import App from './App.vue'
App.vue.vue 文件是 Vue 的单文件组件(SFC),包含 <template>、<script>、<style> 三部分 复制代码import router from './router';
复制代码createApp(App)
.use(router)
.mount('#app')
createApp(App):以 App.vue 为根组件创建应用实例.use(router):安装路由插件,让应用具备路由能力.mount('#app'):将整个 Vue 应用挂载到 id="app" 的 DOM 元素上.use() 返回的仍然是应用实例,所以可以继续 .mount() 复制代码// router/index.js
import {
createRouter, // 创建路由实例
createWebHashHistory // 路由模式
} from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';const routes = [
{
path: '/', // URL 路径
name: 'Home', // 路由名称(可选,用于命名导航)
component: Home // 对应的组件
},
{
path: '/about',
name: 'About',
component: About
}
];const router = createRouter({
history: createWebHashHistory(), // Hash 模式
routes // 路由配置
})export default router;
逐行解析:
复制代码import { createRouter, createWebHashHistory } from 'vue-router';
createRouter:创建路由实例的工厂函数createWebHashHistory:使用 Hash 路由模式,URL 形如 复制代码const routes = [...]
path:URL 路径,/ 表示根路径name:路由名称,可用于 router.push({ name: 'Home' }) 编程式导航component:路径匹配时渲染的组件 复制代码history: createWebHashHistory()
| 模式 | API | URL 格式 | 特点 |
|---|---|---|---|
| Hash 模式 | createWebHashHistory() | /#/about | 不需要服务器配置,兼容性好 |
| History 模式 | createWebHistory() | /about | URL 更美观,需要服务器配置 |
复制代码<!-- App.vue -->
<script setup></script><template>
<div>
<header>
<nav>
<ul>
<!-- router-link 是 vue-router 提供的全局组件 -->
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/about">About</router-link></li>
</ul>
</nav>
</header>
<main>
<!-- 路由匹配到的组件会渲染在这里 -->
<router-view></router-view>
</main>
<footer>
</footer>
</div>
</template><style scoped></style>
逐行解析:
复制代码<router-link to="/">Home</router-link>
router-link 是 vue-router 注册的全局组件<a href="#/">Home</a>to 属性指定目标路径,支持字符串和对象两种写法 复制代码<router-view></router-view>
/#/ 时,渲染 Home.vue/#/about 时,渲染 About.vue 复制代码<!-- views/Home.vue -->
<template>
<div>Home</div>
</template>
复制代码<!-- views/About.vue -->
<template>
<div>About</div>
</template>
这两个是最简单的页面组件,只有 <template> 部分。
Vue 单文件组件(SFC)的三种写法:
| 写法 | 示例 | 适用场景 |
|---|---|---|
| 只有 template | <template>...</template> | 纯展示型页面 |
| template + script | <template>...</template><script setup>...</script> | 有交互逻辑的页面 |
| template + script + style | 完整三件套 | 有独立样式的页面 |
复制代码/* style.css */
:root {
--text: #6b6375;
--bg: #fff;
--accent: #aa3bff;
/* ... */
color-scheme: light dark;
}@media (prefers-color-scheme: dark) {
:root {
--text: #9ca3af;
--bg: #16171d;
--accent: #c084fc;
/* ... */
}
}
关键点解析:
复制代码:root {
--text: #6b6375;
}
:root 是 CSS 的根选择器,匹配 <html> 元素--text 是 CSS 变量(自定义属性),可以在任何地方通过 var(--text) 使用 复制代码@media (prefers-color-scheme: dark) { ... }
复制代码// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'export default defineConfig({
plugins: [vue()],
})
defineConfig:提供类型提示的配置函数plugins: [vue()]:安装 Vue 插件,让 Vite 能处理 .vue 文件| 构建工具 | 开发服务器 | 生产构建 | 特点 |
|---|---|---|---|
| Webpack | 打包后启动 | 打包 | 生态成熟,配置复杂 |
| Vite | 原生 ESM | Rollup | 启动快,配置简单 |
| Turbopack | 原生 ESM | - | Next.js 专用,Rust 实现 |
复制代码用户在浏览器访问 #/about
↓
浏览器加载 index.html,执行 main.js
↓
createApp(App).use(router).mount('#app')
↓
Vue Router 解析 URL 中的 hash:/#/about
↓
匹配到 routes 中 path: '/about' 的配置
↓
渲染 About.vue 组件到 <router-view> 的位置
↓
用户看到 "About" 页面
| 环节 | 传统 DOM 编程 | Vue 组件化开发 |
|---|---|---|
| 页面切换 | 浏览器刷新,重新请求 HTML | router-link 无刷新跳转 |
| 组件复用 | 复制粘贴 HTML | import 引入,直接当标签用 |
| 样式隔离 | 全局污染 | <style scoped> 组件级隔离 |
| 路由管理 | 后端路由,每个 URL 一个 HTML | 前端路由,一个 HTML 动态切换 |
| 构建工具 | 不需要 | Vite/Webpack 处理模块化 |
这个项目虽然简单,但它搭建起了 Vue 开发的完整骨架: