第 1 课:项目启动流程
这节课只解决一个核心问题:
浏览器打开页面之后,这个 Vue 项目到底是怎么一步一步跑起来的?
如果这个问题你没有真正搞懂,后面学组件、路由、状态管理时就会一直"会用但不清楚整体"。
这节课要看哪些文件
这节课只看 3 个文件:
src/main.tssrc/App.vuesrc/router/index.ts
你先不要急着看太多文件。
初学阶段最容易犯的错误,就是文件一多就开始乱。
一句话先讲结论
这个项目的启动顺序可以先记成一句话:
index.html -> main.ts -> App.vue -> RouterView -> 当前路由页面
如果再展开一点,就是:
- 浏览器先加载
index.html index.html再加载src/main.tsmain.ts创建 Vue 应用main.ts注册 Pinia、Router、Element Plusmain.ts把应用挂到#app- 根组件
App.vue里面渲染<RouterView /> - 路由系统根据当前地址决定显示哪个页面组件
先理解 index.html
你虽然暂时主要学 Vue,但 index.html 仍然是入口起点。
它现在最关键的两行是:
html
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
这两行的作用分别是:
<div id="app"></div>
这是 Vue 最终要挂载进去的根节点。<script type="module" src="/src/main.ts"></script>
这表示整个前端应用从main.ts启动。
所以你要先建立一个意识:
main.ts 不是普通文件,它是整个项目的程序入口。
逐步理解 src/main.ts
1. 它负责创建整个 Vue 应用
最关键的一行是:
ts
const app = createApp(App)
这里的意思不是"创建一个页面",而是:
创建整个前端应用实例,并且以 App.vue 作为根组件
你可以把它理解成:
createApp(...)是启动器App.vue是最外层根组件app是整个项目的应用对象
2. 它负责注册插件
后面这几行:
ts
app.use(pinia)
app.use(router)
app.use(ElementPlus)
作用分别是:
app.use(pinia)
让整个项目都可以使用 Pinia 状态管理。app.use(router)
让整个项目都可以使用路由跳转与页面切换。app.use(ElementPlus)
让整个项目都能直接使用 Element Plus 组件。
这里你要理解"插件注册"的概念:
use 的意思不是"用一下",而是"把一个能力安装到整个应用上"。
装完之后,所有组件都能共享这份能力。
3. 它负责把应用挂载到页面上
最后这行:
ts
app.mount('#app')
它的意思是:
把前面创建好的整个 Vue 应用,挂载到 index.html 里的 #app 节点上
这一步很重要,因为它是"Vue 世界"和"真实 HTML 页面"接起来的地方。
如果没有这一步:
- Vue 应用虽然创建了
- 但浏览器页面里不会真正显示出来
src/main.ts 你现在必须记住的职责
以后看到 main.ts,你第一反应应该是:
- 入口文件
- 创建应用
- 注册插件
- 挂载应用
只要你以后做新项目,main.ts 基本都会承担这几个职责。
理解 src/App.vue
这个文件现在非常简单,简单是好事,因为它能帮你看清本质。
核心代码是:
vue
<template>
<RouterView />
</template>
它的意思是:
App.vue 不负责写所有页面内容,它只负责提供一个页面出口`
这里的 <RouterView /> 是 Vue Router 提供的一个特殊组件。
它的职责只有一个:
显示当前地址对应的页面组件
比如:
- 当前地址是
/login,它就显示LoginView.vue - 当前地址是
/dashboard,它就显示仪表盘页面 - 当前地址是
/tasks,它就显示任务页
所以你可以把 App.vue 理解成:
整个应用的总门框,而 RouterView 是门框里的展示窗口
理解 src/router/index.ts
这是路由系统的总控制中心。
它负责的事情很多,但你当前先掌握 4 件事:
- 定义有哪些页面
- 定义每个地址对应哪个组件
- 定义哪些页面需要登录后才能访问
- 定义切换页面后浏览器标题怎么改
第一部分:创建路由实例
最外层这段:
ts
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [...]
})
你先这样理解:
createRouter(...)
创建整个项目唯一的路由实例createWebHistory(...)
使用正常网址风格的路由模式routes
所有页面路由配置都写在这里
第二部分:路由表到底在做什么
例如这段:
ts
{
path: '/login',
name: 'login',
component: () => import('@/views/LoginView.vue'),
}
它的意思是:
- 当地址是
/login - 路由名称叫
login - 显示的页面组件是
LoginView.vue
再比如:
ts
{
path: '/',
redirect: '/dashboard',
}
它表示:
如果用户访问根路径 /,就自动跳到 /dashboard
这就是"重定向"。
第三部分:为什么有 children
你会看到主布局这段结构:
ts
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
children: [...]
}
这里的意思是:
这些子页面不会单独裸着显示,
它们会先进入 MainLayout.vue,再显示到布局内部的 <RouterView /> 里。
这就是后台项目里非常常见的一种结构:
- 外层是统一布局
- 内层是具体页面
所以现在这个项目其实有两层"页面出口":
App.vue里的<RouterView />MainLayout.vue里的<RouterView />
你以后一定要熟悉这种嵌套路由结构。
第四部分:什么是路由守卫
这一段最值得认真看:
ts
router.beforeEach((to) => {
...
})
这叫"全局前置守卫"。
意思是:
每次跳转到新页面之前,都会先经过这里检查一次
当前项目里,它主要做两件事:
- 如果页面需要登录,但用户还没登录,就强制跳去
/login - 如果用户已经登录,却还访问登录页,就直接送去
/dashboard
这就是权限控制的基础写法。
你可以把它理解成门卫:
- 合法就放行
- 不合法就拦截并改道
第五部分:为什么这里能拿到用户登录状态
路由文件里用了这个:
ts
const userStore = useUserStore(pinia)
这说明:
- 路由守卫不是组件
- 但它仍然需要读取全局状态
- 所以它通过共享的
pinia实例来访问userStore
这个点你先不用死记语法,先记住原因:
路由守卫要判断是否登录,所以它必须能读到用户状态
第六部分:afterEach 又是干什么的
后面还有:
ts
router.afterEach((to) => {
document.title = ...
})
这叫"全局后置钩子"。
意思是:
路由切换完成之后,再执行这里的逻辑
当前它做的是统一修改浏览器标签页标题。
这样做的好处是:
- 每个页面都能有自己的标题
- 不需要在每个页面里自己手动写
document.title - 标题逻辑统一集中管理
你现在应该能画出的运行流程图
请你脑子里先画出下面这个流程:
text
浏览器打开页面
->
加载 index.html
->
执行 main.ts
->
createApp(App)
->
注册 Pinia / Router / Element Plus
->
mount('#app')
->
渲染 App.vue
->
渲染 RouterView
->
router 根据当前地址匹配页面
->
必要时先经过 beforeEach 守卫
->
最终显示对应页面组件
->
afterEach 修改浏览器标题
如果这条链你能讲顺,说明你已经真正开始进入 Vue 项目的"整体理解"了。
这一课最容易混淆的点
1. main.ts 和 App.vue 谁更外层
正确理解:
main.ts是程序入口文件App.vue是根组件
所以:
main.ts 先启动应用,App.vue 再作为根组件被加载`
2. RouterView 和路由配置谁负责什么
正确理解:
- 路由配置负责"决定应该显示谁"
RouterView负责"把这个页面显示出来"
3. 登录判断为什么不写在每个页面里
因为那样会重复。
更合理的做法是:
把访问权限判断统一放到路由守卫里
这就是"集中管理"的思维。
你现在应该能回答的 8 个问题
如果下面 8 个问题你都能回答出来,说明这节课已经学到位了:
index.html和main.ts的关系是什么?createApp(App)到底创建了什么?app.use(...)的本质是什么?app.mount('#app')为什么必须有?App.vue现在为什么只有一个<RouterView />?- 路由表里的
path、name、component各自代表什么? beforeEach为什么适合做登录校验?afterEach为什么适合做页面标题处理?
这节课的动手练习
你现在不要急着继续加功能,先做这几个最小练习:
练习 1
把 src/router/index.ts 里默认重定向从:
ts
redirect: '/dashboard'
改成:
ts
redirect: '/tasks'
然后运行项目,观察首页默认进入哪里。
目的:
理解"重定向"真的会影响默认落地页。
练习 2
把某个页面的 meta.title 改掉,比如把"任务管理"改成"任务中心",然后看浏览器标签页标题是否变化。
目的:
理解 afterEach 和 meta.title 的联动关系。
练习 3
在未登录状态下手动访问 /tasks,观察是否会先被送到 /login。
目的:
理解路由守卫在真实访问过程中的作用。
这节课的复习结论
最后把最核心的内容压缩成 6 句话:
index.html是网页入口壳子,main.ts是 Vue 项目入口文件。main.ts负责创建应用、注册插件、挂载应用。App.vue是根组件,现在主要负责提供路由出口。RouterView负责把当前地址匹配到的页面显示出来。router/index.ts负责定义页面映射关系和访问规则。beforeEach管权限,afterEach管页面切换后的收尾逻辑。
下一课预告
下一课我会继续整理成 Markdown,并讲这两个重点:
MainLayout.vue为什么是后台项目里最常见的布局结构- 登录页和路由守卫是怎么配合完成跳转控制的
等你下一次说"继续",我就按这个格式继续写第 2 课。