创建Vite Vue3项目
Vue3路由怎么快速上手?还有哪些进阶坑和实用技巧?
Vue3正式发布已经快4年了,越来越多的项目从Vue2迁移过来或者直接基于Vue3开发,而路由作为前端单页应用(SPA)的核心骨架,自然是大家必学的内容,很多刚接触Vue3的同学可能会觉得,不就是把vue-router从3.x升到4.x吗?改几个API就行?其实没那么简单——虽然基础逻辑没变,但composition-api的融入、一些核心机制的调整、以及官方推荐写法的变化,都会让你的开发体验天差地别,今天咱们就从新手入门一步步讲,再唠唠那些踩过坑才会知道的细节和能提效的小技巧。
先搞懂:Vue3用的vue-router 4.x和3.x到底有啥不一样?
很多教程一上来就教你“npm i vue-router@4”然后写代码,但我建议你先花3分钟理清版本差异,不然碰到3.x的老代码照抄会懵,碰到4.x的新API也不知道为啥要用。
核心差异主要集中在3个方面:
第一,安装和注册方式完全变了,3.x里你是用new VueRouter()创建实例,然后在new Vue的时候传进去;4.x改成了createRouter(),而且必须配合Vue3的createApp()一起用,不能直接挂载到构造函数原型上了——毕竟Vue3连构造函数都不怎么推荐直接new全局实例了,composition-api更倾向于按需引入。
第二,组件里访问路由的方式变了,3.x里不管是setup外还是setup内,都可以用this.$router或者this.$route;4.x里setup是在组件实例创建前执行的,根本拿不到this,所以官方专门给了两个组合式API:useRouter和useRoute,setup外的话其实还是保留了this.$router/this.$route,但既然用了Vue3,建议还是全用组合式的写法更统一。
第三,模式配置变了,3.x里hash模式是mode: 'hash',history模式是mode: 'history';4.x改成了用工厂函数创建history对象:hash模式用createWebHashHistory(),history模式用createWebHistory(),还有一个用于SSR的createMemoryHistory(),这个变化是为了让路由的历史管理逻辑更模块化,方便扩展和维护。
入门三步曲:从零搭一个带导航栏和简单页面的Vue3路由demo
讲完差异,咱们直接上手实操,不用复杂的脚手架配置,用Vite快速起个项目就行——毕竟Vite和Vue3是官方CP,开发体验比Webpack快太多了。
第一步:初始化项目并安装vue-router 4.x
打开终端,找个你喜欢的文件夹,输入以下命令:
# 进入项目目录 cd vue3-router-demo # 安装依赖 npm install # 安装vue-router 4.x npm install vue-router@4
安装完依赖后,你可以先在浏览器里打开项目看看默认界面(npm run dev),然后咱们开始改代码。
第二步:创建基础路由配置和页面组件
在src目录下新建一个router文件夹,然后在里面建一个index.js文件——这是官方推荐的路由配置文件位置,方便管理。 在src目录下新建一个views文件夹,用来放我们的页面级组件(普通组件放在components文件夹就行,和views分开是前端SPA的通用规范,方便维护和区分),咱们先建3个简单的页面:Home.vue、About.vue、404.vue。
先写views里的页面: Home.vue:
<template>
<div class="home">
<h1>这是首页</h1>
<p>欢迎来到我的Vue3路由demo!</p>
<button @click="goToAbout">点我跳转到关于页</button>
</div>
</template>
<script setup>
// 这里先用一下useRouter,后面会详细讲
import { useRouter } from 'vue-router'
const router = useRouter()
const goToAbout = () => {
router.push('/about')
}
</script>
<style scoped>
.home {
padding: 20px;
}
button {
padding: 8px 16px;
margin-top: 10px;
cursor: pointer;
}
</style>
About.vue:
<template>
<div class="about">
<h1>这是关于页</h1>
<p>这是一个关于Vue3路由的demo页面</p>
<router-link to="/">返回首页</router-link>
</div>
</template>
<style scoped>
.about {
padding: 20px;
}
router-link {
color: #42b983;
text-decoration: none;
}
router-link.active {
text-decoration: underline;
}
</style>
vue:
<template>
<div class="not-found">
<h1>404!页面走丢了</h1>
<p>你访问的页面不存在哦,<router-link to="/">返回首页</router-link>吧</p>
</div>
</template>
<style scoped>
.not-found {
padding: 20px;
text-align: center;
color: #ff6b6b;
}
</style>
接下来写router/index.js配置文件:
import { createRouter, createWebHistory } from 'vue-router'
// 引入刚才创建的页面组件
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import NotFound from '../views/404.vue'
// 定义路由规则,每个规则对应一个页面
const routes = [
{
// 路径,用户访问这个路径时会渲染对应的组件
path: '/',
// 路由名称,可选,但推荐写上,后面用name跳转更方便,尤其是路径改了的时候不用改所有跳转代码
name: 'home',
// 对应的组件,这里是直接引入的,也可以用懒加载,后面进阶会讲
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
{
// 通配符路由,必须放在最后!用户访问任何不存在的路径都会匹配到这个
path: '/:pathMatch(.*)*',
name: 'not-found',
component: NotFound
}
]
// 创建路由实例
const router = createRouter({
// 历史模式,这里用的是web history模式,也就是没有#的那种,部署的时候需要配置服务器
history: createWebHistory(import.meta.env.BASE_URL),
// 刚才定义的路由规则
routes
})
// 导出路由实例,供main.js使用
export default router
这里提个小细节:createWebHistory里的参数是import.meta.env.BASE_URL,这是Vite提供的环境变量,默认是'/',如果你部署到服务器的子目录下(比如https://example.com/my-app),就需要在vite.config.js里把base改成'/my-app/',这里会自动读取,不用手动改两次。
第三步:在main.js里注册路由,在App.vue里设置导航栏和路由出口
最后一步,把路由挂载到Vue实例上,然后设置一下导航栏和<router-view>(路由出口,匹配到的页面组件会渲染在这里)。
先改main.js:
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 引入刚才导出的路由实例
import router from './router'
// 创建Vue实例
const app = createApp(App)
// 注册路由
app.use(router)
// 挂载到DOM上
app.mount('#app')
再改App.vue:
<template>
<!-- 导航栏,用<router-link>代替<a>标签,这样可以避免页面刷新,体验更好 -->
<nav>
<!-- to属性就是要跳转的路径,也可以用to="{ name: 'home' }"的对象写法 -->
<router-link to="/">首页</router-link> |
<router-link to="/about">lt;/router-link>
</nav>
<!-- 路由出口,核心!匹配到的页面组件会在这里渲染 -->
<router-view />
</template>
<style>
/* 全局样式,稍微美化一下导航栏 */
nav {
padding: 20px;
background-color: #f0f0f0;
}
nav a {
margin: 0 10px;
color: #333;
text-decoration: none;
}
/* router-link-active是默认的激活类名,当路由匹配到当前链接时会自动添加这个类,你可以自己改样式 */
nav a.router-link-active {
color: #42b983;
font-weight: bold;
}
</style>
好了!现在你可以保存所有文件,终端里输入npm run dev,打开浏览器看看,应该就能看到一个带导航栏和首页、关于页、404页的demo了——点击导航栏的链接,或者首页的按钮,页面不会刷新,内容会动态切换,这就是SPA的魅力。
进阶实战:掌握这几个核心功能,日常开发完全够用
刚才的demo只是入门,日常开发中我们还会碰到动态路由、路由传参、路由懒加载、路由守卫这些需求,下面咱们一个个讲。
动态路由——如何实现带ID的详情页?
比如我们有一个新闻列表页,点击某条新闻要跳转到对应的新闻详情页,路径可能是/news/123,这里的123就是新闻的ID,是动态变化的,这时候就需要用到动态路由。
我们在views文件夹下新建一个News.vue(新闻列表页)和NewsDetail.vue(新闻详情页): News.vue:
<template>
<div class="news">
<h1>新闻列表</h1>
<ul>
<!-- 模拟3条新闻 -->
<li v-for="news in newsList" :key="news.id">
<!-- 用to的对象写法,传入动态参数id -->
<router-link :to="{ name: 'news-detail', params: { id: news.id } }">
{{ news.title }}
</router-link>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 模拟新闻数据
const newsList = ref([
{ id: 1, title: 'Vue3.4发布了!新增了这些实用功能' },
{ id: 2, title: 'Vite 5.0更新,构建速度再提升30%' },
{ id: 3, title: '前端就业现状分析:202X年该如何提升自己?' }
])
</script>
<style scoped>
.news {
padding: 20px;
}
li {
margin: 10px 0;
}
</style>
NewsDetail.vue:
<template>
<div class="news-detail">
<h1>{{ news?.title || '加载中...' }}</h1>
<p>新闻ID:{{ route.params.id }}</p>
<p>新闻内容:这里是新闻详情内容,实际开发中可以根据route.params.id从后端接口获取</p>
<router-link to="/news">返回新闻列表</router-link>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRoute } from 'vue-router'
// 引入useRoute,用来获取当前路由的信息,包括路径、参数、查询字符串等
const route = useRoute()
// 模拟新闻数据
const newsList = ref([
{ id: 1, title: 'Vue3.4发布了!新增了这些实用功能' },
{ id: 2, title: 'Vite 5.0更新,构建速度再提升30%' },
{ id: 3, title: '前端就业现状分析:202X年该如何提升自己?' }
])
// 根据当前路由的params.id获取对应的新闻
const news = computed(() => newsList.value.find(item => item.id === Number(route.params.id)))
</script>
<style scoped>
.news-detail {
padding: 20px;
}
</style>
我们在router/index.js里添加这两个路由规则:
// 在routes数组里添加,注意通配符路由还是要放在最后
{
path: '/news',
name: 'news',
component: () => import('../views/News.vue') // 这里用了懒加载,后面讲
},
{
// 动态路由用冒号:开头,后面跟着参数名
path: '/news/:id',
name: 'news-detail',
component: () => import('../views/NewsDetail.vue')
}
还要在App.vue的导航栏里加一个新闻列表的链接:
<nav> <router-link to="/">首页</router-link> | <router-link to="/news">新闻列表</router-link> | <router-link to="/about">lt;/router-link> </nav>
现在你可以试试,点击新闻列表里的链接,会跳转到对应的详情页,路径里会有对应的ID,而且详情页会显示对应的新闻标题——是不是很简单?
这里提个重要的点:动态路由的params参数,如果用<router-link>的对象写法或者router.push({ name: 'xxx', params: {...} })的话,参数是不会显示在URL里的吗?不对不对,刚才的例子里params是显示在URL里的——什么时候显示什么时候不显示?记住这个规则:如果参数是定义在路由规则的path里的(比如/news/:id),那么用name+params跳转时,参数会自动拼接到URL里;如果参数没有定义在path里,那用name+params跳转时,参数会保存在内存里,刷新页面就会丢失,所以推荐所有可能需要刷新页面后还保留的参数,要么定义在path里(params),要么放在查询字符串里(query)。
查询字符串怎么用?比如路径是/news?id=123,跳转的时候可以用<router-link :to="{ path: '/news', query: { id: 123 } }">,获取的时候用route.query.id,这个参数会一直显示在URL里,刷新页面也不会丢失,适合用来做分页、筛选这类功能。
路由懒加载——如何减小首屏加载体积?
刚才的News.vue和NewsDetail.vue我用了懒加载的写法,也就是component: () => import('../views/News.vue'),而不是像Home.vue那样直接引入,为什么要用懒加载?
因为直接引入的话,所有页面组件的代码都会打包到一个JS文件里,首屏加载的时候就会把所有页面的代码都下载下来,不管用户需不需要——如果你的项目有几十个甚至上百个页面,首屏加载体积会非常大,用户体验会很差。
而懒加载的话,只有当用户访问到这个页面的时候,才会下载对应的JS文件,这样可以大大减小首屏加载体积,提升首屏加载速度。
懒加载的写法很简单,刚才已经演示过了,就是把component的值改成一个箭头函数,函数里用import()动态引入组件——这个import()是ES6的动态导入语法,浏览器支持度已经非常好了,不用太担心兼容性问题(如果要兼容老旧浏览器,可以用Babel转译)。
Vite还支持自动分包,你不用做额外的配置,每个懒加载的组件都会被打包成一个单独的JS文件,非常方便。
嵌套路由——如何实现带侧边栏的后台管理系统?
后台管理系统是前端开发中非常常见的场景,通常会有一个顶部导航栏,一个侧边栏,然后中间是内容区域——这时候就需要用到嵌套路由,也就是在一个路由规则里再定义子路由。
我们在views文件夹下新建一个Admin.vue(后台管理系统的主框架页),然后在Admin.vue里再建一个侧边栏组件和两个子页面:Dashboard.vue(仪表盘)、UserManage.vue(用户管理)——或者直接把侧边栏写在Admin.vue里,子页面放在views/Admin文件夹下更规范,咱们规范一点:
先建views/Admin文件夹,然后在里面建Dashboard.vue、UserManage.vue: Dashboard.vue:
<template>
<div class="dashboard">
<h1>仪表盘</h1>
<p>这里是后台管理系统的仪表盘,可以显示一些统计数据</p>
</div>
</template>
<style scoped>
.dashboard {
padding: 20px;
}
</style>
UserManage.vue:
<template>
<div class="user-manage">
<h1>用户管理</h1>
<p>这里是后台管理系统的用户管理页,可以添加、删除、修改用户</p>
</div>
</template>
<style scoped>
.user-manage {
padding: 20px;
}
</style>
然后建Admin.vue:
<template>
<div class="admin">
<header>后台管理系统</header>
<div class="main">
<!-- 侧边栏,这里的router-link的to是相对于父路由的,也就是/admin/dashboard -->
<aside>
<router-link to="/admin/dashboard">仪表盘</router-link>
<router-link to="/admin/user-manage">用户管理</router-link>
</aside>
<!-- 嵌套路由的出口!子页面组件会渲染在这里 -->
<main>
<router-view />
</main>
</div>
</div>
</template>
<style scoped>
.admin {
height: 100vh;
display: flex;
flex-direction: column;
}
header {
height: 60px;
background-color: #333;
color: #fff;
display: flex;
align-items: center;
padding: 0 20px;
font-size: 20px;
}
.main {
flex: 1;
display: flex;
}
aside {
width: 200px;
background-color: #f0f0f0;
padding: 20px;
display: flex;
flex-direction: column;
gap: 10px;
}
aside a {
color: #333;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
}
aside a.router-link-active {
background-color: #42b983;
color: #fff;
}
main {
flex: 1;
padding: 0;
}
</style>
在router/index.js里添加嵌套路由规则:
// 在routes数组里添加
{
path: '/admin',
name: 'admin',
component: () => import('../views/Admin.vue'),
// 子路由规则,放在children数组里
children: [
{
// 空路径,当用户访问/admin时,会自动匹配到这个子路由
path: '',
// 重定向到/admin/dashboard,这样用户访问/admin时不会显示空白
redirect: { name: 'admin-dashboard' }
},
{
// 子路由的path不需要加前面的/admin,因为是相对于父路由的
path: 'dashboard',
name: 'admin-dashboard',
component: () => import('../views/Admin/Dashboard.vue')
},
{
path: 'user-manage',
name: 'admin-user-manage',
component: () => import('../views/Admin/UserManage.vue')
}
]
}
然后在App.vue的导航栏里加一个后台管理的链接:
<nav> <router-link to="/">首页</router-link> | <router-link to="/news">新闻列表</router-link> | <router-link to="/about">lt;/router-link> | <router-link to="/admin">后台管理</router-link> </nav>
现在你可以试试,点击后台管理的链接,会跳转到一个带顶部导航、侧边栏和仪表盘内容的页面,点击侧边栏的链接,中间的内容区域会动态切换——这就是嵌套路由的典型应用。
这里提个小技巧:子路由里的空路径+重定向是非常常用的,不然用户访问父路由(admin)时,中间的<router-view>会显示空白,体验不好。
路由守卫——如何实现登录验证?
登录验证是几乎所有有用户体系的项目都需要的功能:当用户访问需要登录的页面(比如后台管理系统)时,如果用户没有登录,就跳转回登录页;如果用户已经登录,就可以正常访问——这时候就需要用到路由守卫。
vue-router 4.x里的路由守卫主要有3种:全局前置守卫、路由独享守卫、组件内守卫,咱们今天主要讲最常用的全局前置守卫,因为登录验证通常是全局的。
我们在views文件夹下新建一个Login.vue(登录页):
<template>
<div class="login">
<h1>登录</h1>
<div class="form">
<label>
用户名:
<input type="text" v-model="username" />
</label>
<label>
密码:
<input type="password" v-model="password" />
</label>
<button @click="login">登录</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const username = ref('')
const password = ref('')
// 模拟登录函数
const login = () => {
// 这里只是模拟,实际开发中应该调用后端接口
if (username.value === 'admin' && password.value === '123456') {
// 登录成功,把token或者用户信息保存到localStorage里
localStorage.setItem('token', 'fake-token-123456')
// 跳转到之前要访问的页面,如果没有就跳转到首页
const redirect = router.currentRoute.value.query.redirect || '/'
router.push(redirect)
} else {
alert('用户名或密码错误!')
}
}
</script>
<style scoped>
.login {
padding: 20px;
max-width: 400px;
margin: 50px auto;
}
.form {
display: flex;
flex-direction: column;
gap: 15px;
margin-top: 20px;
}
.form label {
display: flex;
flex-direction: column;
gap: 5px;
}
.form input {
padding: 8px;
font-size: 16px;
}
.form button {
padding: 10px;
font-size: 16px;
background-color: #42b983;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
然后在router/index.js里添加登录页的路由规则,并且配置全局前置守卫:
// 在routes数组里添加,注意顺序,通配符还是最后
{
path: '/login',
name: 'login',
component: () => import('../views/Login.vue')
}
// 配置全局前置守卫,放在createRouter之后,export default之前
router.beforeEach((to, from, next) => {
// to:即将要进入的目标路由对象
// from:当前导航正要离开的路由对象
// next:一个函数,必须调用它来resolve这个钩子,否则导航会一直挂起
// 注意:vue-router 4.x里虽然还保留了next,但官方更推荐直接return一个值或者Promise,咱们这里还是用next,因为更直观,新手容易理解
// 模拟需要登录的页面路径数组
const authRequiredPaths = ['/admin', '/admin/dashboard', '/admin/user-manage']
// 判断即将要进入的页面是否需要登录
const isAuthRequired = authRequiredPaths.some(path => to.path.startsWith(path))
// 判断用户是否已经登录(检查localStorage里有没有token)
const isLoggedIn = localStorage.getItem('token')
if (isAuthRequired && !isLoggedIn) {
// 需要登录但没登录,跳转到登录页,并且带上redirect参数,方便登录成功后跳转回来
next({ name: 'login', query: { redirect: to.fullPath } })
} else {
// 不需要登录或者已经登录,正常放行
next()
}
})
这里提个重要的点:全局前置守卫会在每次路由跳转前执行,所以一定要注意性能,不要在里面做太复杂的操作——如果需要做复杂的权限验证,可以结合Pinia(Vue3官方推荐的状态管理库)一起用。
还有,刚才的authRequiredPaths数组是硬编码的,实际开发中更推荐在路由规则的meta字段里配置权限信息,这样更灵活: 比如在Admin.vue的路由规则里加meta:
{
path: '/admin',
name: 'admin',
component: () => import('../views/Admin.vue'),
// meta字段,用来存储路由的元信息,比如是否需要登录、页面标题等
meta: { requiresAuth: true },
children: [
// 子路由会继承父路由的meta,所以不用每个子路由都加
{
path: '',
redirect: { name: 'admin-dashboard' }
},
{
path: 'dashboard',
name: 'admin-dashboard',
component: () => import('../views/Admin/Dashboard.vue')
},
{
path: 'user-manage',
name: 'admin-user-manage',
component: () => import('../views/Admin/UserManage.vue')
}
]
}
然后全局前置守卫改成:
router.beforeEach((to, from, next) => {
// 直接检查to.meta.requiresAuth,或者to.matched.some(record => record.meta.requiresAuth)——因为子路由会继承父路由的meta,所以用some更稳妥,避免父路由有meta子路由没有的情况
const isAuthRequired = to.matched.some(record => record.meta.requiresAuth)
const isLoggedIn = localStorage.getItem('token')
if (isAuthRequired && !isLoggedIn) {
next({ name: 'login', query: { redirect: to.fullPath } })
} else {
next()
}
})
这样是不是更灵活了?以后如果要给某个页面加权限,只要在它的路由规则里加meta: { requiresAuth: true }就行,不用改全局前置守卫的代码。
避坑指南:这几个常见的坑,90%的新手都会踩
刚才讲了这么多实用功能,现在咱们来唠唠那些踩过坑才会知道的细节,帮你少走弯路。
坑一:setup里拿不到this.$router/this.$route
这个刚才入门的时候已经提过了,setup是在组件实例创建前执行的,根本拿不到this,所以一定要用useRouter和useRoute——别再像3.x那样在setup里写this.$router.push了,会报错的。
坑二:通配符路由没有放在最后
通配符路由(/:pathMatch(.*)*)必须放在routes数组的最后!因为路由匹配是按顺序来的,前面的规则匹配到了就不会再往后看了——如果你把通配符路由放在前面,那所有路径都会匹配到404页,其他页面根本访问不了。
坑三:路由懒加载的路径写错了
路由懒加载用的是import()动态导入,路径必须是相对路径,或者是别名路径——比如你在vite.config.js里配置了别名指向src目录,那可以写成@/views/News.vue,这样更方便,不用写一堆../。
怎么配置别名?在vite.config.js里加:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入path模块,用来处理路径
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
// 配置@别名指向src目录
'@': path.resolve(__dirname, './src')
}
}
})
坑四:web history模式部署后刷新页面404
这个是很多新手部署项目时都会碰到的问题——web history模式下,URL里没有#,看起来更美观,但服务器会把这个URL当成是一个真实的文件路径去查找,比如你访问https://example.com/about,服务器会去找根目录下的about.html文件,如果找不到就会返回404。
怎么解决?需要配置服务器,让所有的请求都指向index.html——因为SPA只有一个index.html文件,所有的路由都是前端控制的。
不同的服务器配置方法不一样:
- Nginx:在nginx.conf里加
try_files $uri $uri/ /index.html; - Apache:在项目根目录下建一个.htaccess文件,里面写一些重写规则
- Vercel、Netlify这些静态托管平台:通常会有自动配置的选项,或者在项目根目录下建一个vercel.json或者netlify.toml文件配置
具体的配置方法可以搜索对应的服务器文档,这里就不展开讲了。
坑五:路由传参时params刷新页面丢失
刚才讲动态路由的时候已经提过了,只有定义在路由规则path里的params,刷新页面才不会丢失;没有定义在path里的params,刷新页面就会丢失,不如用query。
实用技巧:这几个小技巧能让你的开发效率翻倍
给大家分享几个我平时开发中常用的小技巧,能让你的代码更简洁、更高效。
用name跳转代替path跳转
刚才入门的时候已经提过了,用name跳转更方便,尤其是路径改了的时候,不用改所有跳转代码——比如你把/about改成/about-us,只要改路由规则里的path就行,所有用name: 'about'跳转的地方都不用动。
用路由元信息设置页面标题
刚才讲全局前置守卫的时候提到了meta字段,除了配置权限信息,还可以配置页面标题——这样每次路由跳转时,浏览器的标题栏都会自动更新,不用在每个页面组件里单独写document.title。
比如在路由规则里加meta.title:
{
path: '/',
name: 'home',
component: Home,
meta: { title: '首页 - 我的Vue3路由demo' }
},
{
path: '/about',
name: 'about',
component: About,
meta: { title: '- 我的Vue3路由demo' }
}
然后在全局前置守卫里加:
router.beforeEach((to, from, next) => {
// 设置页面标题,如果meta里没有title,就用默认标题
document.title = to.meta.title || '我的Vue3路由demo'
// 权限验证的代码...
next()
})
用keep-alive缓存路由组件
有些页面(比如新闻列表页),用户跳转到详情页再返回时,希望保留之前的滚动位置和搜索条件——这时候就需要用到<keep-alive>组件,它可以缓存路由组件的状态,避免重复渲染。
怎么用?在App.vue里的<router-view>外面包一层<keep-alive>:
<template>
<nav>...</nav>
<!-- include属性是可选的,用来指定哪些组件需要缓存,值是组件的name属性 -->
<!-- exclude属性是可选的,用来指定哪些组件不需要缓存 -->
<!-- max属性是可选的,用来指定最多缓存多少个组件,超过的话会自动销毁最久未使用的组件 -->
<keep-alive include="Home,News">
<router-view />
</keep-alive>
</template>
注意:include和exclude的值是组件的name属性,所以需要在对应的组件里设置name: 比如Home.vue里加:
<script setup>
// 组合式API里设置组件name的方法:用defineOptions
defineOptions({
name: 'Home'
})
// 其他代码...
</script>
用路由别名
路由别名可以让你用不同的路径访问同一个页面——比如你希望用户访问/home和/都能访问到首页,就可以用路由别名。
怎么用?在路由规则里加alias属性:
{
path: '/',
name: 'home',
component: Home,
meta: { title: '首页 - 我的Vue3路由demo' },
// 别名,可以是一个字符串,也可以是一个数组
alias: ['/home']
}
用编程式导航的replace方法
刚才讲编程式导航的时候用的是router.push(),它会向历史记录栈里添加一条新的记录——如果你希望用户点击浏览器的返回按钮时,不会返回到之前的页面(比如登录成功后,用户点击返回不应该回到登录页),就可以用router.replace(),它会替换当前的历史记录。
比如刚才Login.vue里的login函数可以改成:
const login = () => {
if (username.value === 'admin' && password.value === '123456') {
localStorage.setItem('token', 'fake-token-123456')
const redirect = router.currentRoute.value.query.redirect || '/'
// 用replace代替push
router.replace(redirect)
} else {
alert('用户名或密码错误!')
}
}
今天咱们从vue-router 4.x和3.x的差异讲起,然后一步步搭了一个带导航栏、动态路由、嵌套路由、路由懒加载、路由守卫的demo,最后还分享了一些避坑指南和实用技巧。
其实vue-router 4.x的核心逻辑和3.x是一样的,都是基于路径匹配来渲染对应的组件,只是加入了composition-api的支持,调整了一些API和机制——只要你掌握了这些核心功能和细节,日常开发中99%的路由需求都能解决。
如果你还想深入学习vue-router 4.x,可以去官方文档看看,里面有更详细的API说明和示例。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


