路由模式有三种模式
Hash模式: 使用 URL 的 hash 值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器。默认使用的是 hash 模式,也就是会出现如 URL:URL中带有#号。
History模式: 以来 HTML5 History API 和服务器配置。
Abstract模式: 支持所有 javascript 运行模式。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
route/index.js
import { createRouter,//创建路由 createWebHistory,//历史模式 createWebHashHistory,//哈希模式} from 'vue-router'import { Toast } from 'vant';import NProgress from 'nprogress'; // Progress 进度条import 'nprogress/nprogress.css'; // Progress 进度条 样式import store from "../store/index";const xqlist = ()=>import("@/views/xiang/xiang")//用变量形式导入const routes = [ { path: "/",//url访问的路径 name: "tabBar",//路由名称 component: ()=>import("@/components/lib/tabBar/index"),//页面导入路径 redirect:{name:'index',query:{id:55}},//域名重定向 alias: /home,//路由别名, children:[//子页面 // 首页 { path: "/index", name: "index", alias:['/a', '/b', '/c'],//多个别名,alias: ['/:id',''] component: ()=>import("@/views/index/index"), meta: {//meta里面属性,都可以自定义。 title: '首页',//用于在渲染的时候配置浏览器标题 keepAlive: true, }, beforeEnter: (to, from) => {//也可以这样单个写路由独享守卫。 document.title = to.meta.title }, }, // 发现首页 { path: "/findIndex/:id",//:id(动态路由) name: "findIndex", meta: { title: '发现', keepAlive: true, }, component: ()=>import("@/views/find/findIndex/findIndex") }, // 我的首页 { path: "/mineIndex", name: "mineIndex", meta: { title: '我的', keepAlive: true, requireAuth: true//跳转时候通过这个标识,路由导航检测是否需要验证已登录的 }, component: ()=>import("@/views/mine/mineIndex/mineIndex") } ] }, { path: "/xiang", name: "xiang", meta: { title: '详情页', }, component: ()=>import("@/views/xiang/xiang") //component: xqlist //或者以变量形式导入 }, {//404 路由页面配置 path: "/:pathMatch(.*)*", name: "404", component: ()=>import("@/views/lib/404") },];const router = createRouter({ mode: 'hash', history: createWebHistory(process.env.BASE_URL),//历史模式 //history: createWebHashHistory(process.env.BASE_URL),//哈希模式 base: process.env.BASE_URL, // 配置激活时要使用的类名 linkActiveClass:'router-link-active', routes});NProgress.configure({ showSpinner: false});//前置守卫,在路由跳转前触发。router.beforeEach()//全局解析守卫,在导航被确认前,同时在组件内守卫和异步路由组件被解析后router.beforeResolve()//后置守卫,在路由跳转完成后触发。router.afterEach()//导航守卫主要用来通过跳转或取消的方式守卫导航//前置守卫,to即将要进入的目标路由对象, from当前导航正要离开的路由router.beforeEach((to, from, next) => { const title = to.meta.title//使用路由元信息meta实现动态页面标题 document.title = title NProgress.start(); // 开启Progress if (to.meta.requireAuth) { // 判断该路由是否需要登录权限 if (store.state.token) { // 通过vuex state获取当前的token是否存在 next(); } else { console.log(to.fullPath); next() } } else { next(); }});// 后置守卫router.afterEach((to, from) => { Toast.clear(); NProgress.done(); // 结束Progress});export default router;
路由参数传递方式
- 传递参数主要有两种类型:params 和 query
params 的类型:
- 配置路由格式: /user/:id (动态路由)
- 传递的方式: 在 path 后面对应的值 :to=”’/user/‘+uid”
- 传递后形成的路径: /user/9, /user/zx
- 接收参数: $route.params.id
query 的类型:
- 配置路由格式: /user, 正常配置
- 传 递 的 方 式 : 对 象 中 使 用 query 的 key 作 为 传 递 方 式 :to={ path:’/‘,query:{id:1,name:’abc’}}
- 传递后形成的路径:/user?id=9, /user?id=zx
- 接收参数:$route.query.name
<router-link to="/xiang">详情</router-link>等价于route.push({name:’xiang’})
| 写法 |
说明 |
| $route.path |
字符串,对应当前路由的路径,总是解析为绝对路径,如”/foo/bar”。 |
| $route.params |
一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。 |
| $route.query |
当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。锚点* |
| $route.fullPath |
完成解析后的 URL,包含查询参数和hash的完整路径。 |
| $route.matched |
数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。 |
| $route.name |
当前路径名字 |
| $route.meta |
路由元信息 |
<template> <!-- query传递单一的方式 --> <router-link :to="'/user/page/'+item.id">{{item.title}}</router-link> <!-- query传递必须使用path路径 --> <router-link :to="{ path:'/xiang',<!-- 路由路径 --> query:{user:'query小张zhang'}<!-- query传递数据,会显示在URL上面,类似get。 --> }" replace<!-- replace属性的作用是页面切换时不会留下历史记录 --> exact<!-- exact是开启“router-link”的严格模式 --> custom<!-- 是否不渲染成a标签 --> >query传递</router-link> <!-- params传递必须使用name路由名称 --> <router-link :to="{ name:'xiang',<!-- 路由名称 --> params:{user:'params小张zhang'}<!-- params传递数据,不会显示在URL上面,类似POST。 --> }" >params传递</router-link></template>
组件守卫导航
| 函数沟子名 |
含义 |
触发时机说明 |
| onBeforeRouteUpdate |
组件内更新守卫 |
在当前路由改变啊,但是该组件被复用时调用 |
| onBeforeRouteLeave |
组件内离开守卫 |
导航离开该组件路由时调用 |
原生路由对应VUE路由
| 原生 |
VUE |
| window.history.pushState |
router.push |
| window.history.replaceState |
router.replace |
| window.history.go |
router.go |
import { useRoute,//路由信息 useRouter,//操作路由 onBeforeRouteUpdate,//更新(当前重复)路由调用 onBeforeRouteLeave,//离开当前路由调用 RouterLink, useLink} from 'vue-router';//引入路由import { onMounted,watch,watchEffect } from 'vue';consy router = useRouter()function gopage(){ this.$router.push({path:'/xiang',query:{a:123}})//选项式写法 this.$router.replace({path:'/xiang',query: {a:123}})//选项式写法,replace属性的作用是页面切换时不会留下历史记录 router.push({name:'xiang',params: {user:'按钮小张zhang'}})//组合式写法 router.push({path:'/xiang',query: {user:'按钮小张zhang'}})//组合式写法 router.go(1)//前进一页,和router.forward() 相同 router.go(-1) // 后退一页,和router.back()相同。 /* router.go(n)和原生window.history.go(n)类似 */}// 查询文章详情async function queryArticleDetail(id: number) { // 请求接口数据 const res = await axios({ url: `/article/${id}`, })}onMounted(() => { route.params})/* 用法1、比如一个内容网站,通常在文章详情页底部会有相关阅读推荐,这个时候就会有一个操作场景是,从文章 A 跳转到文章 B。2、比如从 https://www.baidu.com/article/111 请求 https://www.baidu.com/article/222 ,这种情况就属于 “路由改变,但是组件被复用” 的情况了。3、这种情况下,原本放在 onMounted 里执行数据请求的函数就不会被调用,可以借助该钩子来实现渲染新的文章内容。*/onBeforeRouteUpdate(async (to, from) => { // ID 不变时减少重复请求 if (to.params.id === from.params.id) return // 注意这里是获取 `to` 的 `params` const id = Number(to.params.id) || 0 await queryArticleDetail(id)})/*用法可以在离开当前路由之前,实现一些离开前的判断拦截。离开守卫通常用来禁止用户在还未保存修改前突然离开,可以通过 return false 来取消用户离开当前路由。*/onBeforeRouteLeave((to, from) => { // 弹出一个确认框 const confirmText = '确认要离开吗?您的更改尚未保存!' const isConfirmLeave = window.confirm(confirmText) // 当用户点取消时,不离开路由 if (!isConfirmLeave) { return false }})/*侦听整个路由第一个参数传入整个路由;第二个参数是个 Callback ,可以获取 to 和 from 来判断路由变化情况。*/watch(route, (to, from) => { // 处理一些事情})/*侦听路由的某个数据如果只想侦听路由的某个数据变化,比如侦听一个Query或者一个Param,可以采用这种方式:*/watch( () => route.query.id, () => { console.log('侦听到 ID 变化') })/*直接侦听包含路由参数的那个函数对比 watch 的使用, watchEffect在操作上更加简单,把包含要被侦听数据的函数,当成它的入参传进去即可。*/watchEffect(queryArticleDetail)
部署问题与服务端配置
通常使用路由的 Hash哈希 模式,部署后有问题的情况很少,但是如果使用 History历史 模式,可能会遇到这样那样的问题。
常见部署问题
这里整理一些常见部署问题的原因分析和解决方案,可作参考。
页面刷新就 404
页面部署到服务端之后,访问首页正常;通过导航上面的链接进行路由跳转,也正常;但是刷新页面就变成 404 了。
问题原因
一般这种情况是路由开启了 History 模式,但是服务端没有配置功能支持。
解决方案
请根据 服务端配置 部分的说明,与的运维同事沟通,让他帮忙修改服务端的配置。
部分路由白屏
如果在项目配置文件里,把里面的 publicPath (使用 Vue CLI ) 或者 base (使用 Vite ) 配置成相对路径 ./ ,但是路由配置了二级或以上,那么就会出现这个问题。
问题原因
原因是打包后的 JS 、 CSS 等静态资源都是存放在项目根目录下,一级路由的 ./ 就是根目录,所以访问正常;而二级路由的 ./ 则不是根目录了,是从当前目录载入的 ,这就导致无法正确载入 JS 文件,从而导致了白屏。
解决方案
如果的项目开启了 History 模式,并且配置有二级或者二级以上的路由时,不要使用 ./ 这样的相对路径。
正确的方式应该是修改 publicPath (使用 Vue CLI ) 或者 base (使用 Vite ),如果是部署在域名根目录则写 / ,如果是子目录,则按照子目录的格式,将其以 / 开头,以 / 结尾的形式配置( e.g. /hello-world/ )
服务端配置方案
如果使用的是 HTML5 的 History 模式,那么服务端也需要配置对应的支持,否则会出现路由跳转正常,但页面一刷新就 404 的情况。