共计 5595 个字符,预计需要花费 14 分钟才能阅读完成。
路由
后台路由是根据请求 url,匹配请求处理的后台模块(路径)
前台根据访问路径,决定显示的内容。
路由就是:访问 hash 与内容的对应关系
路由的工作方式
- 用户点击页面的路由链接
- 导致 url 地址栏中的 Hash 值发生了变化
- 前端路由监听到 Hash 地址的变化
- 前端路由将当前 Hash 地址对应的组件渲染在浏览器中。
如何实现一个路由
核心逻辑:
在 created 函数中通过 window.onhashchange 监听路由变化触发组件切换。
核心代码如下:
<template>
<a href="#/tab1">tab1</a>
<a href="#/tab2">tab2</a>
<a href="#/tab3">tab2</a>
<component :is="comName"></component>
</template>
<script>
import Tab1 from './components/Tab1.vue';
import Tab2 from './components/Tab2.vue';
import Tab3 from './components/Tab3.vue';
export default {
name: 'App',
components: {
Tab1,
Tab2,
Tab3
},
created() {window.onhashchange = () => {switch (location.hash) {
case "#/tab1":
this.comName = "tab1"
break
case "#/tab2":
this.comName = "tab2"
break
case "#/tab3":
this.comName = "tab3"
break
}
}
},
data() {
return {comName: "Tab1"}
}
}
</script>
使用 vue-router
基本用法 - 如何使用
安装
https://router.vuejs.org/zh/installation.html
定义组件
使用链接与占位符
使用 \<router-link> 标签来声明路由链接,并使用 \<router-view> 标签来声明路由占位符
创建路由模块
①从 vue-router 中按需导入两个方法
②导入需要使用路由控制的组件
③创建路由实例对象
④向外共享路由实例对象
import {createRouter, createWebHistory} from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('@/views/AboutView.vue')
}
]
})
export default router
⑤在 main.js 中导入并挂载路由模块
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
高级用法
嵌套路由
也可以使用 \<router-view> 继续嵌套 \<router-view> 实现多层的嵌套视图。
上层 routeview 切换到 home 与 test 页面
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/test">test</RouterLink>
<RouterView />
{
path: '/',
name: 'home',
component: HomeView,
},
{
path:'/test',
name: 'test',
component: TestPage,
children:[{ path: 'tab1',component: TabView1},
{path: 'tab2',component: TabView2}
]
},
下层 routeview test 页面 (TestPage) 核心配置:可以切换到 tab1 tab2 页签
<router-link to="/test/tab1" >tab1</router-link>
<router-link to="/test/tab2" >tab2</router-link>
<router-view />
动态路由
动态路由指的是:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中使用英文的冒号(:)来定义路由的参数项。示例代码如下:
{path: 'tab/:id',component: TabView},
现在像 /test/tab/1 和 /test/tab/2 都会映射到同一个组件。
路径参数 用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 route.params 的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID:
<template>
<div>
<!-- 当前路由可以通过 $route 在模板中访问 -->
this is tab {{$route.params.id}}
</div>
</template>
动态路由参数传递:可以通过设置 props: true 来配置路由将 id 参数作为 prop 传递给组件:
// 路由配置
{path: 'tab/:id',component: TabView, props:true},
// 页面配置
<template>
this is tab: {{id}}
</template>
<script>
export default {props:['id']
}
</script>
- 路由的匹配规则
https://router.vuejs.org/zh/guide/essentials/route-matching-syntax.html重定向 redirect 和别名
重定向
路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C,从而展示特定的组件页面。通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
重定向也是通过 routes 配置来完成,下面例子是从 /home 重定向到 /:
在写 redirect 的时候,可以省略 component 配置
<RouterLink to="/test">About</RouterLink>
// 访问的虽然是 /test,但是会跳转到 /about
{
path:'/test',
name: 'test',
redirect:'/about',
},
重定向的目标也可以是一个命名的路由:redirect: {name: 'testpage'}
也可以是一个方法,动态返回重定向目标:{
// /search/screens -> /search?q=screens
path: '/search/:searchText',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径 / 路径对象
return {path: '/search', query: { q: to.params.searchText} }
},
},
{
path: '/search',
// ...
- redirect: to => {...} 说明
redirect:这是 Vue Router 中路由配置对象中的一个选项,用于指定路由重定向规则。
to:这是一个函数参数,代表目标路由对象,包含了路由的相关信息,比如参数、路径等。
to => {...}:这是一个箭头函数,接收 to 参数,并返回一个对象,用于描述重定向的目标路由。
在你的示例中,当用户访问 /search/:searchText 路由时,会触发重定向到 /search 路由,并将 searchText 参数的值作为查询参数 q 的值传递过去。这样可以实现将动态路径参数转换为查询参数的功能。
相对重定向
{
// 将总是把 /users/123/posts 重定向到 /users/123/profile。path: '/users/:id/posts',
redirect: to => {
// 该函数接收目标路由作为参数
// 相对位置不以 `/` 开头
// 或 {path: 'profile'}
return 'profile'
},
},
别名 -alias
设置别名意味着多个 url 对应一同一个内容
如将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。
{
path: '/users',
component: UsersLayout,
children: [
// 为这 3 个 URL 呈现 UserList
// - /users
// - /users/list
// - /people
{path: '', component: UserList, alias: ['/people', 'list'] },
],
}
编程式导航
除了使用 \
声明式
<router-link :to="...">
编程式:
router.push(...)
将之前的标签触发,改为函数触发
<button @click="goTab(2)" >tab2</button>
methods:{goTab(id){this.$router.push("/test/tab/"+id)
}
}
导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
全局导航守卫会拦截每个路由规则,从而对每个路由进行访问权限的控制。可以按照如下的方式定义全局导航守卫:
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
守卫方法接收参数:
- to: 即将要进入的目标 用一种标准化的方式
- from: 当前导航正要离开的路由 用一种标准化的方式
- next: 新版本当前为可选参数,next 是一个函数,通过调用它以验证导航。如果守卫的回调函数中有返回值,则可以省略 next,如果传递了该参数,请确保它被严格调用一次,否则页面将会卡住,无法顺利跳转或展示数据。
它的执行效果依赖调用时所传递的参数:
next() 不传递参数时,会进行管道中的下一个钩子
next(false) 中断当前的导航
next('/otherPath') 或者 next({path: '/otherPath'}) 当前的导航被中断,然后进行一个新的导航,跳转到一个不同的地址
传递对象可以定制跳转的方式,如 next({replace: true, name: 'home'}) 以取代历史记录的方式,跳转导航到首页。
next(error) 传入 next 的参数是一个 Error 实例,则导航会被终止
可以返回的值如下
- false: 取消当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
- 一个路由地址: 通过一个路由地址重定向到一个不同的地址,如同调用 router.push(),且可以传入诸如 replace: true 或 name: 'home' 之类的选项。它会中断当前的导航,同时用相同的 from 创建一个新导航。
- 如果返回 true、undefined 或者不返回任何值(即默认返回 undefined),则路由会继续进行,即允许路由跳转。
则导航是有效的,并调用下一个导航守卫
// 这里不需要 next
router.beforeEach(async (to, from) => {
if (
// 检查用户是否已登录
!isAuthenticated &&
// ❗️ 避免无限重定向
to.name !== 'Login'
) {
// 将用户重定向到登录页面
return {name: 'Login'}
}
})
//async 这里是异步,意味着在路由修改之前,可以有其他操作比如页面显示元素的变化,不如 loading 页面等,可以先操作。
更多相关内容
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
案例
案例源码
https://github.com/nebofeng/Vue3_demo/tree/master/04-vue-router
用到的知识点
- 嵌套路由、动态路由相关
效果
文章首发于:https://nebofeng.com/2024/11/10/vue3-06_%e8%b7%af%e7%94%b1/