创建 404 组件(如 NotFound.vue
):
404 页面不存在
您访问的路径不存在
返回首页
配置通配符路由(需放在所有路由规则最后):
// Vue Router 4(Vue 3)
const router = createRouter({
routes: [
// 其他路由...
{
path: '/:pathMatch(.*)*', // 匹配所有未定义路径
name: 'NotFound',
component: () => import('@/views/NotFound.vue')
}
]
})
// Vue Router 3(Vue 2)
const router = new VueRouter({
routes: [
// 其他路由...
{ path: '*', component: NotFound }
]
})
获取未匹配路径:在 404 组件中通过 $route.params.pathMatch
获取原始路径:
您访问的路径 "{{ $route.params.pathMatch }}" 不存在
重定向到指定 404 页面:
{
path: '/:pathMatch(.*)*',
redirect: { name: 'NotFound' } // 重定向到命名路由
}
路由守卫中动态处理 404:
router.beforeEach((to, from, next) => {
// 检查页面是否存在(如通过 API 验证)
if (!isValidPage(to.path)) {
next({ name: 'NotFound' })
} else {
next()
}
})
过滤器用于数据格式化,可在模板中通过 |
符号调用,例如:
{{ date | formatDate }}
{{ price | formatCurrency }}
场景 | 示例代码 |
---|---|
日期格式化 | js Vue.filter('formatDate', val => new Date(val).toLocaleDateString()) |
货币格式化 | js Vue.filter('formatCurrency', val => ¥${val.toFixed(2)}) |
文本截断 | js Vue.filter('truncate', (val, len) => val.slice(0, len) + '...') |
首字母大写 | js Vue.filter('capitalize', val => val.charAt(0).toUpperCase() + val.slice(1)) |
替代方式 | 示例代码 | 优势 |
---|---|---|
计算属性 | js computed: { formattedDate() { return new Date(this.date).toLocaleDateString() } } |
响应式依赖,自动更新 |
方法 | js methods: { formatDate(val) { return new Date(val).toLocaleDateString() } } |
可接收参数,灵活调用 |
局部过滤器 | js export default { filters: { formatDate(val) { /* 逻辑 */ } } } |
组件内复用,保持代码封装性 |
对比项 | computed(计算属性) | methods(方法) |
---|---|---|
缓存机制 | 依赖数据不变时缓存结果,仅重新计算依赖变化时的值。 | 每次调用都重新执行函数,无缓存。 |
响应式更新 | 自动监听依赖数据变化,实时更新。 | 不自动响应数据变化,需手动调用。 |
调用方式 | 作为属性访问({{ computedValue }} ),无需括号。 |
作为函数调用({{ methodsFn() }} ),必须加括号。 |
使用场景 | 适用于复杂数据处理(如多数据派生)、频繁访问的场景。 | 适用于事件处理、副作用操作(如 API 调用)、动态参数场景。 |
性能 | 依赖不变时性能更高(无需重复计算)。 | 每次调用都消耗性能,不适合频繁调用。 |
数据流向 | 强调数据转换(只读,默认不可修改)。 | 强调行为操作(可修改组件状态)。 |
计算属性结果:{{ doubleNum }}
方法调用结果:{{ doubleNumMethod() }}
当 num
不变时,多次访问 doubleNum
只输出一次日志,而 doubleNumMethod()
每次访问都输出日志。
前端路由的本质是在单页面应用(SPA)中,通过监听 URL 变化来动态切换页面内容,而不重新加载整个页面。Vue 前端路由的核心功能包括:监听 URL、匹配路由规则、渲染对应组件、更新历史记录。
Vue Router 是 Vue 官方路由库,通过以下核心组件和步骤实现路由功能:
创建路由实例:定义路由规则和组件映射。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
const router = createRouter({
history: createWebHistory(), // 路由模式(见下文)
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
export default router
注册路由插件:在 Vue 应用中全局注册路由。
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
在组件中使用路由:通过 $router
(导航)和 $route
(当前路由信息)操作路由。
嵌套路由:支持多层级路由结构,构建复杂布局。
const routes = [
{
path: '/user/:id',
component: User,
children: [
{ path: 'profile', component: UserProfile },
{ path: 'posts', component: UserPosts }
]
}
]
动态路由参数:通过 :param
匹配动态路径,如 /user/123
中的 123
。
{ path: '/user/:id', component: User }
命名视图:同时渲染多个组件(如主内容区和侧边栏)。
路由守卫:控制导航流程(如登录验证)。
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn) {
next('/login') // 未登录则重定向到登录页
} else {
next()
}
})
路由懒加载:按需加载组件,优化性能。
const UserDetails = () => import('./views/UserDetails.vue')
Vue Router 支持三种路由模式,核心区别如下:
模式 | 实现原理 | URL 示例 | 兼容性 | 服务器配置 | SEO 友好性 |
---|---|---|---|---|---|
Hash 模式 | 利用 URL 中的哈希值(# ),哈希变化不会触发页面刷新,由前端处理。 |
http://example.com/#/home |
全浏览器兼容 | 无需服务器配置 | 差(哈希不被索引) |
History 模式 | 利用 HTML5 History API (pushState /replaceState ),URL 更美观。 |
http://example.com/home |
需浏览器支持 HTML5 | 必须配置服务器(见下方) | 好(完整 URL 可索引) |
Abstract 模式 | 不依赖浏览器环境(如 Node.js 服务端渲染),路由状态保存在内存中。 | 无实际 URL | 仅服务端可用 | 无需浏览器支持 | 不适用 |
Vue Router 支持三种主要的路由模式,每种模式都有其独特的实现原理和适用场景。下面从多个维度对比它们的区别:
#
)作为路由标识,哈希值的变化不会触发页面刷新,由前端 JavaScript 监听哈希变化并处理路由逻辑。http://example.com/#/home
原理:利用 HTML5 的 History API
(pushState
和 replaceState
)实现无刷新路由切换,URL 看起来更像传统的静态页面 URL。
URL 格式:http://example.com/home
特点:
index.html
),否则会出现 404 错误。服务器配置示例:
Nginx 配置:
server {
listen 80;
server_name example.com;
root /path/to/your/app;
location / {
try_files $uri $uri/ /index.html; # 关键配置:所有请求重定向到 index.html
}
}
Express 配置:
const express = require('express');
const history = require('connect-history-api-fallback');
const app = express();
app.use(history()); // 处理 History 模式路由
app.use(express.static('public')); // 静态资源路径
app.listen(3000);
适用场景:需要良好 SEO 的应用、企业官网、电商网站等。
原理:不依赖浏览器环境,路由状态保存在内存中,适用于非浏览器环境(如 Node.js 服务端渲染、原生应用等)。
URL 格式:无实际 URL,路由变化通过 JavaScript 方法触发。
特点
:
适用场景:服务端渲染(SSR)应用、Weex/React Native 等原生应用中的路由管理。
特性 | Hash 模式 | History 模式 | Abstract 模式 |
---|---|---|---|
URL 格式 | 带 # 符号 |
普通 URL | 无实际 URL |
兼容性 | 全浏览器支持 | 需 HTML5 History API | 任意 JavaScript 环境 |
服务器配置 | 无需配置 | 必须配置重定向 | 无需配置 |
SEO 友好性 | 差 | 好 | 不适用 |
典型场景 | 小型 SPA、内部应用 | 企业官网、电商网站 | SSR、原生应用 |
router
是 Vue Router 的实例,负责管理路由配置和导航逻辑;route
是当前路由的状态对象,包含当前路由的详细信息。二者核心区别如下:
特性 | router (路由器实例) |
route (当前路由对象) |
---|---|---|
本质 | 全局单例对象,管理整个应用的路由配置和导航流程。 | 局部对象,代表当前激活的路由状态(如路径、参数)。 |
功能 | - 提供导航方法(push 、replace 、go ) - 注册全局守卫(beforeEach ) - 动态管理路由(addRoute ) |
- 存储当前路由信息(path 、params 、query ) - 组件内访问路由参数 - 组件级守卫(beforeRouteEnter ) |
响应式 | 实例本身非响应式,但导航方法会触发路由更新。 | 对象属性是响应式的,路由变化时自动更新。 |
获取方式 | 选项式 API:this.$router 组合式 API:useRouter() |
选项式 API:this.$route 组合式 API:useRoute() |
示例代码 | router.push('/home') (导航到首页) |
console.log(route.params.id) (获取动态参数) |
import { useRouter, useRoute } from 'vue-router'
const router = useRouter() // 获取路由器实例
const route = useRoute() // 获取当前路由对象
// 导航到用户详情页(携带参数)
router.push({ name: 'user', params: { id: route.params.id } })
// 监听路由参数变化(响应式)
watch(() => route.params.id, (newId) => {
fetchUserData(newId) // 参数变化时重新获取数据
})
路由守卫是 Vue Router 提供的导航控制机制,用于在路由跳转过程中拦截、验证或修改导航行为。它分为三类:全局守卫、路由独享守卫和组件内守卫,核心作用是实现权限控制、数据预加载、离开确认等功能。
beforeEach
:路由跳转前触发,常用于登录验证、权限检查。
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn) {
next('/login') // 未登录则重定向到登录页
} else {
next() // 允许跳转
}
})
beforeResolve
:在组件内守卫之后、导航确认前触发,用于处理异步数据加载。
afterEach
:路由跳转后触发,无 next
参数,常用于记录日志或页面滚动。
在路由配置中通过 beforeEnter
定义,仅对当前路由生效:
const routes = [
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
if (isAdmin) {
next()
} else {
next({ name: 'Forbidden' }) // 无权限则重定向到禁止页
}
}
}
]
在组件内部定义,用于控制组件的进入、更新或离开:
导航流程:
触发导航 → beforeRouteLeave(失活组件)→ beforeEach(全局)→ beforeRouteUpdate(复用组件)→ beforeEnter(路由独享)→ beforeRouteEnter(激活组件)→ beforeResolve(全局)→ 导航确认 → afterEach(全局)→ DOM 更新
注意事项:
next()
才能继续导航,否则会被阻塞。beforeRouteEnter
无法访问组件实例 this
,需通过 next(vm => vm.xxx)
操作组件。next()
在异步操作完成后调用,否则导航会一直等待。路由参数分为路径参数(Params)、查询参数(Query)和 Hash 值,可通过以下方式获取:
$route
对象获取(选项式 API)路径参数:
$route.params.参数名
用户ID:{{ $route.params.id }}
查询参数:
$route.query.参数名
搜索关键词:{{ $route.query.keyword }}
Hash 值:$route.hash
(如 #section1
)。
useRoute
钩子获取(组合式 API)
props
传递参数(推荐解耦方式)在路由配置中启用 props
,将参数作为组件属性传入:
布尔值模式:直接映射路径参数到组件props
// 路由配置
{
path: '/user/:id',
component: User,
props: true // 启用后,User 组件可通过 props 接收 id
}
用户ID:{{ id }}
对象模式
:自定义参数映射(可同时包含路径参数和查询参数)
{
path: '/user/:id',
component: User,
props: route => ({
userId: route.params.id,
queryName: route.query.name,
page: Number(route.query.page) || 1 // 类型转换
})
}
正则匹配:
{ path: '/users/:id(\\d+)' } // 仅匹配数字 ID
{ path: '/:pathMatch(.*)*' } // 匹配所有路径(404 页面)
响应参数变化:当路由参数变化但组件复用时(如/user/1→/user/2),需监听参数变化:
在路由配置中通过 meta
字段存储自定义参数,可在守卫或组件中访问:
// 路由配置
{
path: '/admin',
component: Admin,
meta: {
requiresAuth: true,
roles: ['admin', 'editor']
}
}
// 在守卫中访问
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !checkRole(to.meta.roles)) {
next('/login')
} else {
next()
}
})
在 Vue Router 中,动态路由通过在路径中使用 :
标记参数实现,参数会被解析为对象并绑定到路由实例。
// 定义单个动态参数
{ path: '/users/:id', component: UserComponent }
// 定义多个动态参数
{ path: '/posts/:postId/comments/:commentId', component: CommentComponent }
// 带正则表达式的动态参数(仅匹配数字 ID)
{ path: '/users/:id(\\d+)', component: UserComponent }
通过 this.$route.params
访问动态参数:
用户 ID:{{ $route.params.id }}
通过 useRoute()
钩子获取路由对象后访问参数:
当路由参数变化但组件复用时(如 /user/1
→ /user/2
),需监听参数变化:
通过命名路由更清晰地传递参数:
// 路由配置
{
path: '/user/:username',
name: 'user',
component: User
}
// 编程式导航
router.push({ name: 'user', params: { username: 'john' } })
// 声明式导航
<router-link :to="{ name: 'user', params: { username: 'john' } }">用户详情</router-link>
通过 this.$route
对象访问路由信息:
当前路径:{{ $route.path }}
参数 ID:{{ $route.params.id }}
查询参数:{{ $route.query.keyword }}
通过 useRoute()
钩子获取响应式路由对象:
export default {
watch: {
'$route.params.id'(newId, oldId) {
this.fetchData(newId) // 参数变化时更新数据
}
}
}
钩子函数是一种编程模式,允许在特定事件或流程的关键点插入自定义逻辑,而不修改原有代码。它本质是一种回调函数,由框架或库在特定时机主动调用,用于扩展功能或修改行为。
在组件生命周期的不同阶段自动调用,例如:
export default {
beforeCreate() { console.log('实例初始化前') },
created() { console.log('实例创建完成') },
mounted() { console.log('组件挂载到 DOM') },
beforeUpdate() { console.log('数据更新前') },
updated() { console.log('数据更新后') },
beforeDestroy() { console.log('组件销毁前') }
}
在路由跳转的不同阶段拦截导航,例如:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn) {
next('/login') // 未登录则重定向
} else {
next() // 允许跳转
}
})
在函数组件中处理状态和副作用,例如:
import { useState, useEffect } from 'react'
function Counter() {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `点击了 ${count} 次` // 组件更新后执行
return () => console.log('组件卸载') // 组件卸载时执行
}, [count])
return <button onClick={() => setCount(count + 1)}>点击</button>
}
对比项 | params(路径参数) | query(查询参数) |
---|---|---|
URL 表现形式 | 作为路径的一部分,如 /user/123 (123 是 params) |
以 ?key=value 形式附加在 URL 后,如 /user?id=123 |
路由定义 | 需要在路由路径中用 : 声明(如 path: '/user/:id' ) |
无需在路由中声明,可随时附加 |
参数访问方式 | 通过 $route.params.id 或 route.params.id 访问 |
通过 $route.query.id 或 route.query.id 访问 |
必填性 | 若路由定义了 params,导航时必须传递,否则路径不匹配 | 可选,导航时可传可不传 |
刷新保留 | 刷新页面后 params 仍存在于路径中 | 刷新页面后 query 仍存在于 URL 查询字符串中 |
典型应用场景 | 标识资源唯一 ID(如用户详情页 /user/123 ) |
传递过滤条件、分页参数(如 /list?page=2&size=10 ) |
active-class
是
组件的属性,用于自定义链接激活时的 CSS 类名。当链接对应的路由被激活时,Vue Router 会自动为该链接添加 active-class
指定的类名,默认类名为 router-link-active
。
首页
关于
.nav-active {
color: #3498db;
font-weight: 500;
}
.nav-exact-active {
border-bottom: 2px solid #3498db;
}
Vue 路由跳转分为声明式导航和编程式导航两种方式,适用于不同场景:
首页
用户详情
搜索
关于
通过路由实例的方法触发跳转,适用于动态逻辑或非 UI 触发的场景:
// 选项式 API 中
this.$router.push('/home') // 跳转到路径
this.$router.push({ name: 'user', params: { id: 123 } }) // 命名路由带参数
this.$router.replace('/about') // 替换当前历史记录
this.$router.go(-1) // 后退一步
// 组合式 API 中
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({ path: '/dashboard', query: { page: 2 } })
在路由守卫中通过返回路由对象实现跳转:
router.beforeEach((to, from, next) => {
if (!isAuthenticated && to.meta.requiresAuth) {
next({ name: 'Login' }) // 未登录则重定向到登录页
} else {
next()
}
})
对比项 | Vue Router 跳转 | location.href 跳转 |
---|---|---|
页面刷新 | 不刷新页面,仅更新视图(SPA 特性) | 刷新整个页面,重新加载所有资源 |
路由控制 | 支持参数传递、路由守卫、动态路由等完整路由系统 | 仅简单 URL 跳转,无路由控制能力 |
历史管理 | 支持 hash 和 history 模式,可管理历史记录 |
仅添加新历史记录,无法控制历史栈 |
状态保留 | 跳转后保留应用状态(如表单数据、滚动位置) | 跳转后丢失所有状态,需重新初始化 |
性能 | 跳转速度快,无需重新请求资源 | 跳转速度慢,需重新加载页面资源 |
适用场景 | 单页应用内部导航 | 跳转到外部网站或需要完整页面刷新的场景 |
// Vue Router 跳转(推荐单页应用内部使用)
this.$router.push('/user/123') // 不刷新,保留应用状态
// location.href 跳转(适用于外部链接或完整刷新)
location.href = 'https://example.com' // 刷新页面,跳转到外部网站
继续
命名路由是为路由设置名称,通过名称而非路径进行导航,使代码更清晰且便于维护。
在路由配置中通过 name
字段命名:
const routes = [
{
path: '/user/:id',
name: 'user', // 命名路由
component: UserComponent
},
{
path: '/post/:id',
name: 'post',
component: PostComponent
}
]
)通过 :to
传递对象,指定 name
和 params
:
用户详情
文章详情
router.push
)// 选项式 API
this.$router.push({ name: 'user', params: { id: 123 } })
// 组合式 API
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({ name: 'post', params: { id: 456 } })
params
时,若参数缺失会抛出错误,避免无效导航。name: 'userProfile'
比路径 /user/:id/profile
更易理解)。