VUE3 路由使用方式和原理
路由模式有三种模式Hash模式: 使用 URL 的 hash 值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器。默认使用的是 hash 模式,也就是会出现如 URL:URL中带有#号。History模式: 以来 HTML5 History API 和服务器配置。Abstract模式: 支持所有 javascript 运行模式。如果发现没有浏览器的 API,路由会自动强制进入这个模式。route/index.js写法
说明
$route.path
字符串,对应当前路由的路径,总是解析为绝对路径,如”/foo/bar”。
$route.params
一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
$route.query
当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。锚点*
$route.fullPath
完成解析后的 URL,包含查询参数和hash的完整路径。
$route.matched
数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
$route.name
当前路径名字
$route.meta
路由元信息
函数沟子名
含义
触发时机说明
onBeforeRouteUpdate
组件内更新守卫
在当前路由改变啊,但是该组件被复用时调用
onBeforeRouteLeave
组件内离开守卫
导航离开该组件路由时调用
原生路由对应VUE路由
原生
VUE
window.history.pushState
router.push
window.history.replaceState
router.replace
window.history.go
router.go
假设项目域名是 https://example.com ,那么:一级路由是 https://example.com/home ,二级路由是 https://example.com/foo/bar ,假设打包后的 JS 文件等静态资产存放于 https://example.com/assets/ 文件夹下访问一级路由时, ./ 访问到的 JS 文件是 https://example.com/assets/home.js ,所以一级路由可以正常访问到。访问二级路由时, ./ 访问到的 JS 文件是 https://example.com/foo/assets/bar.js ,但实际上文件是存放在 https://example.com/assets/bar.js ,访问到的 URL 资源不存在,所以白屏了。解决方案如果的项目开启了 History 模式,并且配置有二级或者二级以上的路由时,不要使用 ./ 这样的相对路径。正确的方式应该是修改 publicPath (使用 Vue CLI ) 或者 base (使用 Vite ),如果是部署在域名根目录则写 / ,如果是子目录,则按照子目录的格式,将其以 / 开头,以 / 结尾的形式配置( e.g. /hello-world/ )服务端配置方案如果使用的是 HTML5 的 History 模式,那么服务端也需要配置对应的支持,否则会出现路由跳转正常,但页面一刷新就 404 的情况。服务器配置方案看官网vue router 不同的历史记录模式【感谢龙石为本站提供数据中台建设http://www.longshidata.com/pages/government.html】
路由参数传递方式
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 和 queryparams 的类型:
- 配置路由格式: /user/:id (动态路由)
- 传递的方式: 在 path 后面对应的值 :to=”’/user/‘+uid”
- 传递后形成的路径: /user/9, /user/zx
- 接收参数: $route.params.idquery 的类型:
- 配置路由格式: /user, 正常配置
- 传 递 的 方 式 : 对 象 中 使 用 query 的 key 作 为 传 递 方 式 :to={ path:’/‘,query:{id:1,name:’abc’}}
- 传递后形成的路径:/user?id=9, /user?id=zx
- 接收参数:$route.query.name
组件守卫导航
<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>
部署问题与服务端配置通常使用路由的 Hash哈希 模式,部署后有问题的情况很少,但是如果使用 History历史 模式,可能会遇到这样那样的问题。常见部署问题这里整理一些常见部署问题的原因分析和解决方案,可作参考。页面刷新就 404页面部署到服务端之后,访问首页正常;通过导航上面的链接进行路由跳转,也正常;但是刷新页面就变成 404 了。问题原因一般这种情况是路由开启了 History 模式,但是服务端没有配置功能支持。解决方案请根据 服务端配置 部分的说明,与的运维同事沟通,让他帮忙修改服务端的配置。部分路由白屏如果在项目配置文件里,把里面的 publicPath (使用 Vue CLI ) 或者 base (使用 Vite ) 配置成相对路径 ./ ,但是路由配置了二级或以上,那么就会出现这个问题。问题原因原因是打包后的 JS 、 CSS 等静态资源都是存放在项目根目录下,一级路由的 ./ 就是根目录,所以访问正常;而二级路由的 ./ 则不是根目录了,是从当前目录载入的 ,这就导致无法正确载入 JS 文件,从而导致了白屏。
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)
假设项目域名是 https://example.com ,那么:一级路由是 https://example.com/home ,二级路由是 https://example.com/foo/bar ,假设打包后的 JS 文件等静态资产存放于 https://example.com/assets/ 文件夹下访问一级路由时, ./ 访问到的 JS 文件是 https://example.com/assets/home.js ,所以一级路由可以正常访问到。访问二级路由时, ./ 访问到的 JS 文件是 https://example.com/foo/assets/bar.js ,但实际上文件是存放在 https://example.com/assets/bar.js ,访问到的 URL 资源不存在,所以白屏了。解决方案如果的项目开启了 History 模式,并且配置有二级或者二级以上的路由时,不要使用 ./ 这样的相对路径。正确的方式应该是修改 publicPath (使用 Vue CLI ) 或者 base (使用 Vite ),如果是部署在域名根目录则写 / ,如果是子目录,则按照子目录的格式,将其以 / 开头,以 / 结尾的形式配置( e.g. /hello-world/ )服务端配置方案如果使用的是 HTML5 的 History 模式,那么服务端也需要配置对应的支持,否则会出现路由跳转正常,但页面一刷新就 404 的情况。服务器配置方案看官网vue router 不同的历史记录模式【感谢龙石为本站提供数据中台建设http://www.longshidata.com/pages/government.html】