在现代 Web 开发中,"工程化"已成为提升开发效率、保障项目质量的关键。本文将围绕 Vite 构建工具 、Vue 3 路由系统(vue-router) 以及 项目入口机制,带你快速搭建一个结构清晰、可维护性强的前端项目,并深入解析其背后的工程化思想。
结论先行:# 在 Hash 路由中的真实作用
#的核心作用并非 "唯一性",而是作为「URL 锚点标识符」,实现前端路由的核心逻辑:隔离哈希值与服务器请求、前端独立控制路由。
一、# 的本质:URL 中的「哈希 / 锚点」
在 URL 中,# 是官方定义的 片段标识符(Fragment Identifier) ,具有以下特性:
- 浏览器行为 :
#及其后的内容(哈希值)不会被发送到服务器,仅在浏览器端生效; - 锚点原生作用 :原本用于定位页面内的锚点(如
<a href="#top">跳转到页面顶部); - Hash 路由的复用 :前端路由框架(Vue Router、React Router)复用这一特性 ,将
#后的内容作为 "前端路由路径",实现无刷新页面跳转。
二、# 的核心作用(与 "唯一性" 无关)
1. 隔离前端路由与服务器请求(核心价值)
例如 URL:http://localhost:5173/#/about
- 浏览器向服务器发送请求时,只传递
http://localhost:5173/,#/about被忽略; - 服务器只需处理根路径,无需关心前端路由;
- 这解决了 单页应用(SPA)刷新 404 的问题------这是 Hash 路由最核心的价值,与"唯一性"完全无关。
2. 前端独立控制路由状态
#后的哈希值变化会触发浏览器的hashchange事件(不会刷新页面);- 框架监听该事件,根据哈希值匹配路由规则,渲染不同组件(如
/about→ 渲染About组件); - 哈希值可自由修改(如
location.hash = '/home'),是前端路由的 "载体" ,而非 "唯一标识"。
3. 附带:可作为页面状态标识(非唯一性)
- 哈希值可用于标记业务状态(如
#/article/123标识文章 ID); - 但这属于 业务层面的标识 ,
#本身只是承载容器; - 哈希值可重复 (比如不同页面手动设为相同
#/test),浏览器不限制。
三、为什么 "唯一性" 是错误认知?
#是 URL 的固定语法符号 ,不是"唯一标识符":所有 Hash 路由都包含#,它是统一的分隔符;- 哈希值本身也不保证唯一:你可以手动设置多个页面为相同哈希;
- 唯一性需业务层面保证 :通过路由规则配置(如
/about、/home不重复)实现,与#无关。
四、Hash 路由 vs History 路由(对比理解 # 的作用)
| 特性 | Hash 模式(带 #) |
History 模式(无 #) |
|---|---|---|
| 服务器请求 | 仅发送 # 前的路径 |
发送完整路径 |
| 刷新 404 问题 | 无(服务器只需处理根路径) | 需服务器配置 (重定向到 index.html) |
| 兼容性 | 更好(支持低版本浏览器) | 依赖 HTML5 History API |
| URL 美观性 | 带 #,相对不美观 |
无 #,更接近原生 URL |
✅ 总结 :
#在 Hash 路由中的核心价值是------利用浏览器对 URL 哈希的原生处理规则,实现前端无刷新路由,同时避免前端路由路径被发送到服务器 。它是 "分隔符 / 载体" ,而非用于保证唯一性的标识。
一、为什么选择 Vite?
Vite 是由 Vue 作者尤雨溪开发的新一代前端构建工具,核心优势在于 极速冷启动 和 即时热更新(HMR) 。
✨ 核心原理
- 利用现代浏览器原生支持的 ES 模块(ESM) ,无需打包即可直接加载模块。
- 开发阶段:按需编译,只处理当前请求的文件,启动速度极快。
- 生产环境:使用 Rollup 打包,兼顾性能与兼容性。
🚀 快速初始化项目
perl
bash
编辑
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
npm run dev
此时,Vite 会:
- 自动打开浏览器(如
http://localhost:5173) - 监听
src/下所有文件变更,实现 毫秒级热更新 - 以
index.html为入口,挂载到<div id="app"></div>
二、标准项目结构解析
Vite + Vue 3 提供了高度规范化的目录结构:
csharp
text
编辑
my-vue-app/
├── index.html # 应用入口 HTML
├── src/
│ ├── main.js # 应用入口 JS
│ ├── App.vue # 根组件
│ ├── style.css # 全局样式
│ ├── components/ # 可复用组件
│ └── views/ # 页面级组件(路由页面)
├── public/ # 静态资源(不参与构建)
└── package.json # 依赖与脚本管理
💡 关键点 :
main.js中通过createApp(App).mount('#app')将 Vue 应用挂载到 DOM。
三、多页面应用:集成 Vue Router
单页应用(SPA)需要路由来切换不同"页面"。Vue 官方推荐使用 vue-router。
第一步:先看整体结构(总览)
这段代码是 Vue 项目中「路由配置文件」(src/router/index.js),核心分为 4 个部分:
- 导入 Vue Router 核心方法 + 页面组件;
- 定义「路由规则数组」(URL 对应哪个组件);
- 创建「路由实例」(把规则和路由模式结合);
- 导出路由实例 (让项目入口文件
main.js能使用)。
下面先看完整代码标注:
javascript
js
编辑
// 1. 导入依赖:从 vue-router 库中拿需要的工具函数
import { createRouter, createWebHashHistory } from 'vue-router'
// 2. 导入页面组件:从 views 目录导入 Home/About 组件(就是你要显示的页面)
import Home from '../views/Home.vue'
import About from '../views/About.vue'
// 3. 定义路由规则:数组里每一个对象就是一条「URL → 组件」的规则
const routes = [
{ path: '/', name: 'Home', component: Home }, // 访问根路径 → 显示 Home 组件
{ path: '/about', name: 'About', component: About } // 访问 /about → 显示 About 组件
]
// 4. 创建路由实例:把规则和路由模式(# 模式)结合,生成可使用的路由对象
const router = createRouter({
history: createWebHashHistory(), // 路由模式:Hash 模式(URL 带 #)
routes // 把上面定义的规则数组传给路由实例
})
// 5. 导出路由实例:让 main.js 能导入并挂载到 Vue 应用上
export default router
第二步:逐行拆解(零基础也能懂)
1. 导入部分:拿工具 + 拿组件
javascript
js
编辑
// 从 vue-router 库中导入两个核心函数:createRouter、createWebHashHistory
import { createRouter, createWebHashHistory } from 'vue-router'
createRouter:创建路由实例的 "工厂函数" ------ 你可以理解为 "造路由的模具",调用它就能生成一个能工作的路由对象;createWebHashHistory:路由模式的 "生成器" ------ 专门生成「Hash 模式」的路由历史(URL 带#,比如http://localhost:5173/#/about);
🔍 补充 :Vue Router 还有另一种模式
createWebHistory()(History 模式,URL 不带#,比如http://localhost:5173/about),但需要后端配置,新手建议先用 Hash 模式。
javascript
js
编辑
// 导入页面组件:../ 表示"上一级目录",即从 router 目录回到 src 目录,再进 views 目录拿组件
import Home from '../views/Home.vue'
import About from '../views/About.vue'
-
../views/Home.vue路径含义(新手重点):- 当前文件在
src/router/index.js,../是 "跳出 router 目录",回到src目录; - 然后进入
views目录,找到Home.vue文件(就是你写的首页组件);
- 当前文件在
-
作用:把页面组件 "拿进来",让路由规则能关联到它。
2. 定义路由规则数组:const routes = [...]
ini
js
编辑
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: About }
]
这是核心规则:数组里的每个对象对应「一个 URL 路径 → 一个页面组件」,每个对象的 3 个核心属性:
| 属性 | 含义 |
|---|---|
path |
访问的 URL 路径(必填) : -- / 表示 "根路径"(如 http://localhost:5173/#/) -- /about 表示 "/about 路径"(如 http://localhost:5173/#/about) |
name |
路由的 "别名"(可选,但推荐加) : 后续可以用 router.push({ name: 'About' }) 跳转,比写路径更灵活,便于后期维护 |
component |
路径对应的页面组件(必填) : 就是你前面导入的 Home/About 组件,访问该路径时,页面就会渲染这个组件 |
3. 创建路由实例:const router = createRouter({...})
scss
js
编辑
const router = createRouter({
history: createWebHashHistory(), // 路由模式
routes // 等价于 routes: routes(ES6 简写)
})
-
createRouter():调用第一步导入的 "造路由模具",传入配置对象,生成一个「路由实例」(可以理解为 "能工作的路由器"); -
history: createWebHashHistory():指定路由的「历史模式」为 Hash 模式,核心特点:- URL 中会带
#(比如#/about),#后面的内容不会发送到后端; - 所以不需要后端配置(新手友好);
- 例如访问
http://localhost:5173/#/about,浏览器只会把http://localhost:5173/发给服务器,#/about由前端路由处理;
- URL 中会带
-
routes:把前面定义的规则数组传给路由实例,告诉路由器 "该怎么匹配 URL 和组件"。
4. 导出路由实例:export default router
arduino
js
编辑
export default router
- 作用 :把创建好的路由实例 "暴露出去",让项目的入口文件(
src/main.js)能导入并挂载到 Vue 应用上; - 类比:就像你造好了一个 "路由器",现在把它拿出来,让整个 Vue 项目能使用这个路由器。
第三步:这个文件的 "配套操作"(必须知道,否则路由不生效)
光写路由配置文件还不够!必须完成以下两步,路由才能真正工作:
1. 在 main.js 中挂载路由
main.js是 Vue 3 项目的入口文件(程序启动的第一个文件) ,负责创建 Vue 应用实例、配置插件、挂载到页面。
逐行拆解如下:
javascript
js
编辑
// 1. import { createApp } from 'vue'
// 从 Vue 核心库导入 createApp 函数(创建应用的"工厂")
// Vue 3 不再用 new Vue(),而是用 createApp 创建独立实例(支持多应用)
import { createApp } from 'vue'
// 2. import App from './App.vue'
// 导入根组件 App.vue ------ 整个应用的"容器"
// 所有页面/组件最终都嵌套在 App.vue 内
import App from './App.vue'
// 3. import router from './router'
// 导入路由实例(来自 src/router/index.js)
// ./router 会被自动识别为 ./router/index.js
import router from './router'
// 4. import './style.css'
// 导入全局样式,作用于整个应用
import './style.css'
// 5. 链式调用:创建 → 注册 → 挂载
createApp(App)
.use(router) // 注册路由插件(启用 <router-link>、<router-view> 等功能)
.mount('#app') // 挂载到 HTML 中的 <div id="app"></div>
💡 链式调用等价写法(更易理解) :
scssjs 编辑 const app = createApp(App) app.use(router) app.mount('#app')
关键概念补充:
- 为什么是
main.js?
Vite/Vue CLI 默认将其作为打包入口,最先执行。 - 模块化(import/export)
router/index.js中export default router,所以这里能import router。 - 单页应用(SPA)
整个项目只有一个 HTML 文件(public/index.html),页面跳转靠路由实现,不刷新。
✅ 一句话总结
main.js的作用 :
导入 Vue 核心工具、根组件、路由和全局样式 → 创建 Vue 应用实例 → 注册路由插件 → 把应用挂载到页面的#app元素上,最终启动整个 Vue 应用。
2. 在 App.vue 中添加路由出口
.vue文件是 Vue 特有的单文件组件格式,一个文件就是一个独立组件,包含三部分:
<template>:结构<script>:逻辑<style>:样式
xml
vue
编辑
<!-- src/App.vue -->
<template>
<div>
<!-- 头部导航 -->
<header>
<nav>
<ul>
<!-- Vue 路由链接:点击不刷新页面 -->
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/about">About</router-link></li>
</ul>
</nav>
</header>
<!-- 主内容区 -->
<main>
<!-- 路由出口:页面组件在此动态渲染 -->
<router-view />
</main>
</div>
</template>
<style scoped>
/* scoped 样式仅作用于当前组件 */
ul { display: flex; gap: 16px; list-style: none; }
</style>
核心标签解释:
| 标签 | 作用 |
|---|---|
<router-link to="..."> |
替代 <a> 的路由导航组件 点击不刷新页面,仅替换 <router-view> 内容 |
<router-view /> |
路由出口(占位符) 访问 / 时显示 Home 组件,访问 /about 时显示 About 组件 |
✅ 运行逻辑:
- 访问
http://localhost:5173/#/→ 匹配path: '/'→ 渲染Home到<router-view>- 点击 "About" → URL 变为
#/about→ 触发hashchange→ 渲染About组件
全程无刷新 ,因为#后内容由前端处理。
第四步:运行逻辑(新手必懂)
当你启动项目(npm run dev)后,整个路由的工作流程如下:
- 浏览器访问
http://localhost:5173/#/
→ 路由实例匹配到path: '/'的规则
→ 把Home组件渲染到App.vue的<router-view>位置
→ 页面显示首页; - 点击
<router-link to="/about">
→ URL 变成http://localhost:5173/#/about
→ 路由实例匹配到path: '/about'的规则
→ 把About组件渲染到<router-view>
→ 页面切换为关于页;
✅ 全程页面不会刷新 (前端路由的核心优势),因为 # 后面的路径由前端处理,不请求后端。
第五步:新手常见疑问解答
❓ 为什么用 createWebHashHistory() 而不是 createWebHistory()?
| 对比项 | Hash 模式(#) |
History 模式(无 #) |
|---|---|---|
| URL 美观度 | ❌ 有 # |
✅ 干净路径 |
| 部署复杂度 | ✅ 任意静态服务器 | ❌ 需配置 fallback(如 Nginx 重定向到 index.html) |
| 兼容性 | ✅ 所有浏览器 | ✅ 现代浏览器(IE 不支持) |
📌 建议 :初学者或静态站点用 Hash 模式 ;生产级 SPA 推荐 History 模式 + 服务端支持。
❓ name: 'Home' 有什么用?
除了通过路径跳转(router.push('/about')),还能通过名称跳转:
php
js
编辑
// 更灵活!后续如果修改 path(比如把 /about 改成 /about-us),
// 只需改路由规则里的 path,不用改所有跳转代码
router.push({ name: 'About' })
❓ 组件必须放在 views 目录吗?
不是强制的 !views 是约定俗成的 "页面级组件" 目录(区别于 components/ 中的功能组件),你也可以用 pages/,只要导入路径对应即可。
四、开发体验增强工具
| 工具 | 作用 |
|---|---|
| Volar(VS Code 插件) | 提供 Vue 3 的语法高亮、智能提示、类型检查 |
| Vue DevTools(浏览器插件) | 调试组件状态、路由、Pinia/Vuex 等 |
⚠️ 注意:禁用旧版 Vetur,避免与 Volar 冲突。
五、总结要点
| 模块 | 关键知识点 |
|---|---|
| Vite | 基于 ESM 的极速开发服务器,无需打包即可运行 |
# 的作用 |
URL 哈希标识符,隔离前端路由与服务器请求,实现无刷新跳转 |
| 路由配置 | 定义 path → component 规则,创建 Hash 模式路由实例 |
main.js |
创建应用 → 注册路由 → 挂载到 #app,启动整个 SPA |
App.vue |
使用 <router-link> 导航 + <router-view> 渲染页面 |
| 工程化思维 | 组件化、模块化、关注点分离(页面 vs 功能组件) |
💬 一句话记住路由核心
这段代码的作用是:创建一个 "Hash 模式" 的路由实例,定义了「根路径显示 Home 组件、/about 路径显示 About 组件」的规则,最后导出这个实例,让整个 Vue 应用能根据 URL 切换页面组件。
六、注意事项
-
路径别名 :Vite 默认不支持
@别名,需手动配置vite.config.js:javascriptjs 编辑 import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, 'src') } } }) -
热更新失效? 检查是否修改了非
.vue/.js文件(如vite.config.js需重启)。 -
TypeScript 支持 :Vite 原生支持,初始化时选择
vue-ts模板即可。
结语
从前端"写页面"到"构建工程",Vite + Vue 3 + vue-router 的组合提供了开箱即用的现代化开发体验。掌握这套工具链,不仅能提升开发效率,更是迈向专业前端工程师的重要一步。