0 路由原理
路由器的两种工作模式:
hash模式:(toB)
地址中永远带着#号,不美观,兼容性较好(#及其后面的内容就是hash值,hash值不会带给服务器);
若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
history模式:(toC)
兼容性较差;路径会提交给后台。
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
hash :window.onhashchange监听路由改变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hash test</title>
</head>
<body>
<p>hash test</p>
<button id="btn1">修改 hash</button>
<script>
//3. hash 变化,包括:
// a. JS 修改 url
// b. 手动修改 url 的 hash
// c. 浏览器前进、后退
window.onhashchange = (event) => {
console.log('old url', event.oldURL)
console.log('new url', event.newURL)
console.log('hash:', location.hash)
}
//1. 页面初次加载,获取 hash
document.addEventListener('DOMContentLoaded', () => {
console.log('hash:', location.hash)
})
//2. JS 修改 url
document.getElementById('btn1').addEventListener('click', () => {
location.href = '#/user'
})
</script>
</body>
</html>
history:window.onpopstate监听路由改变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>history API test</title>
</head>
<body>
<p>history API test</p>
<button id="btn1">修改 url</button>
<script>
//1. 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname)
})
//2. 打开一个新的路由
// 【注意】用 pushState 方式,浏览器不会刷新页面
document.getElementById('btn1').addEventListener('click', () => {
const state = { name: 'page1' }
console.log('切换路由到', 'page1')
history.pushState(state, '', 'page1') // 重要!!
})
//3. 监听浏览器前进、后退
window.onpopstate = (event) => { // 重要!!
console.log('onpopstate', event.state, location.pathname)
}
// 需要 server 端配合,可参考
// https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%BE%8B%E5%AD%90
</script>
</body>
</html>
1 基本使用
v3.5.2
<router-link>: 路由链接, 生成路由链接
<router-view>: 路由视图, 显示当前路由组件
<keep-alive>: 缓存路由组件对象
main.js
import Vue from 'vue';
import router from './router';//index.js可以简写
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
});
router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import {routes} from './routes.js';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',//该模式兼容性差
routes
});
export default router;
router/routes.js
export const routes=[
{
path: '/',
redirect: '/home,//重定向
},
{
path: '/home',
component: Home,
name:'MyHome',//命名路由
},
{
path: '/about',
component: About
},
]
hello.vue
<div id="app">
<h1>Hello App!</h1>
<p>
<!--使用 router-link 组件进行导航:本质是a链接;激活时类名是router-link-active(默认) -->
<router-link to="/home" active-class="active">Go to Home</router-link>
<router-link :to="{name:'MyAbout',params:{id:1}}" replace>Go to About</router-link>
</p>
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
2 嵌套路由
export const routes=[
{
path: '/',
redirect: '/home',
},
{
path: '/home',
component: Home,
redirect: '/home/profile',//嵌套路由重定向
children: [//嵌套路由规则
{
path: 'profile',
component: UserProfile,
},
{
path: 'posts',
component: UserPosts,
},
],
},
{
path: '/about',
component: About
},
]
3 路由传参
$route:路由参数对象:包含params/query/path/fullpath(query参数)/meta
$router:路由器对象:包含控制路由跳转的方法(push/replace/back)
3.0 路由的props配置
作用:让路由组件更方便的收到参数。
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
3.1 params
<router-link to="/about/68">Go to About</router-link>
export const routes=[
{
path: '/',
redirect: '/home',
},
{
path: '/home',
component: Home
},
{
path: '/about/:mid',//使用占位符声明接收params参数
component: About,
props:true,//开启后,组件中可直接访问mid,需要声明接收
},
]
const {mid} = this.$route.params
3.2 query
<!-- 传递参数 -->
<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link
:to="{
path:'/home/message/detail',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
<!-- 接收参数 -->
$route.query.id
4 编程式导航
this.$router.push(‘/home/’+id)//增加一条历史记录
this.$router.replace({name:'MyAbout',params:{id:1}})//替换当前历史记录
this.$router.go()
this.$router.back()
this.$router.forward()
5 导航守卫
导航守卫可以控制路由的访问权限。
5.1 全局守卫
全局前置守卫:初始化时执行、每次路由切换前执行(案例:登录后,才可以访问主页)
全局后置守卫:初始化时执行、每次路由切换后执行(修改网页title)
const router = new VueRouter()
// 全局前置守卫:三个参数
router.beforeEach(function(to, from, next) {
if (pathArr.indexOf(to.path) !== -1) {//判断当前要导航的路由是否需要权限
const token = localStorage.getItem('token')
if (token) {//有权限
next()//有token,放行
} else {
next('/login')//无token,强制登录
}
} else {//无权限
next()//放行
}
})
//全局后置守卫
router.afterEach((to,from)=>{
console.log('afterEach',to,from)
if(to.meta.title){
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})
export default router
注意:next(false)表示不允许跳转
5.2 独享守卫
在路由配置上定义路由独享守卫
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
5.3 组件内守卫
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}
6 路由懒加载
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
7 v4.x
vue-router 3.x结合vue2使用
vue-router 4.x结合vue3使用
主要区别:创建路由模块的方式不同
import {createRouter,createWebHashHistory} from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes,
linkActiveClass:'router-link-active',//激活的 RouterLink 的默认类
})
// 创建并挂载根实例
const app = Vue.createApp({})
app.use(router)
路由跳转
import { useRouter } from 'vue-router';
setup(props, ctx) {
const router = useRouter();
const onClickLeft = () => {
router.go(-1);
ctx.emit('handleBack');
};
return {
onClickLeft,
};
},