一、路由的简单使用
1. 理解
- 一个路由(route)就是一组映射关系(key-value),多个路由需要由路由器(router)进行管理
- 前端路由:key是路径path,value是路由组件xxx.Vue
- vue-router是官方提供的用来实现SPA 的Vue插件
2. 基本使用
2.1 安装vue-router插件
npm i vue-router@3
vue2记得指定版本!
2.2 引入并使用插件
import VueRouter from 'vue-router'
Vue.use(VueRouter)
2.3 创建路由组件
在src下创建views或pages文件夹,专门用于放置路由组件
2.4 编写router配置项
在src下创建router文件夹,创建index.js用于配置路由器
在index.js模块下,引入相关的路由组件
实例化VueRouter,new VueRouter({}) 配置路由器
每个路由是一个对象,path是路径、name是路由名、component是对应的路由组件、meta是路由元信息、mode是路由工作模式…
2.5 注册路由
在入口文件main.js中引入注册路由器router,注意,注册完路由器后,Vue组件实例(包括非路由组件)身上都有了$router
和$route
属性
new Vue({
el: '#app',
render: h => h(App),
router
})
2.6 实现路由跳转(两种方式)
- 声明式导航
- 通过使用
<router-link to=""><router-link/>
自定义组件实现路由的跳转 - 可以添加class类名
- 可以添加active-class="active"路由高亮即激活状态
- 这个自定义组件默认会渲染成带有正确链接的a标签
- 通过使用
- 编程式导航
- 通过给节点添加事件
- 配置对应的method,利用组件实例身上的$router属性的
push()
以及replace()
方法实现路由的跳转
2.7 指定路由组件展示位置
<router-view></router-view>
3. 总结与几个注意点
3.1 路由的简单使用步骤
- 创建路由组件
- 配置路由器
- 注册路由器
3.2 几个注意点
- 路由组件通常存放在 pages 文件夹,一般组件通常存放在 components 文件夹。
- 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载;当然也可以缓存路由组件,使得路由组件保持挂载只是失活。
- 每个组件都有自己的 $route 属性,里面存储着自己的路由信息。
- 整个应用只有一个 router ,可以通过组件的 $router 属性获取到。
二、多级路由(嵌套路由)
1. 配置路由规则
- children配置项,配置子级路由
- 注意:子级路由的path不需要/
routes:[
{
path:'/about',
component:About,
},
{
path:'/home',
component:Home,
children:[ //通过children配置子级路由
{
path:'news', //此处不要写:/news
component:News
},
{
path:'message',
component:Message
},
]
}
]
2. 实现路由跳转(要写完整路径)
命名路由则不需要,看后续三补充
<router-link to="/home/news">News</router-link>
3. 指定路由组件展示位置
<router-view></router-view>
三、直接路由与命名路由
1. 作用
简化路由的跳转
2. 使用方式
在router文件夹下的index.js模块配置路由器是给其中需要命名的路由加入name属性
{
path:'/demo',
component:Demo,
children:[
{
path:'test'
component:Test,
children:[
{ //三级路由
name:'hello' //给路由命名
path:'welcome',
component:Hello,
}
]
}
]
}
3. 命名路由简化跳转的实现
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>
<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>
四、向路由组件传递数据(三种方式)
1. 路由路径携带query参数
1.1 声明式导航的to的值
- to的值可以是字符串型的路径
// 通过这种方式传递的数据是写死的
<router-link to="/home/message/detail?id=666&title=你好">
{{ m.title }}
</router-link>
// 通过v-bind+模板字符串
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
{{ m.title }}
</router-link>
- to的值也可以是一个描述地址的对象,这个对象有path、query、name、params等属性,其中query和params是Object,注意此时需要结合v-bind使用,引号内的内容需要被解析为js
<router-link
:to="{ //直接路由,地址栏变为/home/message/detail?id=m.id&title=m.title
path: '/home/message/detail',
query: { id: m.id, title: m.title },
}"
>
{{ m.title }}
</router-link>
- 传递的query参数被
r
o
u
t
e
接
收
,
可
以
在
另
一
个
组
件
内
通
过
‘
t
h
i
s
.
route接收,可以在另一个组件内通过`this.
route接收,可以在另一个组件内通过‘this.route.query.xxx
获取
- 消息标题:{{ $route.query.title }}
- `
2. 路由路径携带params参数
2.1 携带params参数,在配置路由时需要使用占位符
query则不需要!
{
path: '/home', //1
component: Home,
children: [
{
path: 'news',
component: News //2
},
{
path: 'message',
component: Message, //2
children: [
{
// 给路由命名
name: 'xiangqing',
// params写法需要写 (占位)
path: 'detail/:id/:title',
component: Detail //3
}
]
}
]
},
2.2 传递params参数的两种写法(to)
- 字符串写法(字符串/模板字符串)
<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">跳转</router-link>
- 对象写法 注意必须配合name配置项使用,不能配合path配置项!
<router-link
:to="{
name: 'xiangqing',
params: { id: m.id, title: m.title },
}"
>
{{ m.title }}
</router-link> -->
- 传递的params参数被
$route
接收,可以在另一个组件内通过this.$route.params.xxx
获取 - 如:
<li>消息标题:{{ $route.params.title }}</li>
3. 路由的props配置传递数据
3.1 作用
让路由组件更方便的收到参数
3.2 实现
3.2.1 在配置路由器时,给需要接收数据的路由加入props配置项
写在router文件夹的index.js!!!和配置项name、path同级,注意和组件传值props不是一个捏。
- props配置项的第一种写法:对象(该对象中所有的key-value都会以props形式传给对应的路由组件)
props: {
a: '1',
b: 'hello',
},
- props第二种写法:值为布尔值(若布尔值为真,则会把该路由收到的所有params参数,以props的形式传给对应的路由组件),结合2.2
props: true
- props第三种写法:值为函数(该函数返回的对象中每一组key-value都会以props的形式传给对应的路由组件)
props($route) { // 可以接收参数?????
return {
id: $route.query.id,
title: $route.query.title
}
}
3.2.2在路由组件,使用props配置项接收数据
- 第一种,路由组件需要配置props配置项接收路由props配置项传的值
props: ["a", "b"],
- 第二种和第三种,于是路由组件接收到id和title
props: ["id", "title"],
router-link的replace属性同及编程式to和replace区别
1. 作用
控制路由跳转时操作浏览器历史记录的模式
2. 浏览器的历史记录的两种写入方式
- push是追加历史记录,所以可以后退。
- replace 是替换当前记录,因此不可以后退。
- 路由跳转时候默认为 push
3. 理解
两种的区别是:push是压栈,replace是替换栈顶
4. 开启replace模式
<router-link replace>News</router-link>
或<router-link :replace="true">News</router-link>
五、编程式路由导航
1. 作用
不使用<router-link></router-link>
自定义组件,且在路由跳转前可以实现一些业务
2. 实现
- 通过点击事件配置methods,结合push和replace方法
- push和replace方法来自于VueRouter这个构造函数的原型对象
VueRouter.prototype.push
VueRouter.prototype.push
- 根据原型链,实例对象可以使用其构造函数的原型对象上的方法
- 此处的this是组件实例Vc,具有$router属性 需要再看一下原型链/项目的视频/Vc和Vm的区别
- push和replace方法来自于VueRouter这个构造函数的原型对象
- 这两种方法都可以传入对象作为参数,从而设置name/path跳转到哪个路由以及传递query/params参数,类似于to的值的对象形式
methods: {
pushShow(m) {
// push查看detail
// console.log(this.$router);
this.$router.push({
name: "xiangqing",
query: { id: m.id, title: m.title },
});
},
replaceShow(m) {
// replace查看detail
this.$router.replace({
name: "xiangqing",
query: { id: m.id, title: m.title },
});
},
},
3. 前进后退的api
- this.$router.forward()//前进
- this.$router.back()//后退
- this.$router.go()//可前进也可后退,负数后退正数前进
六、缓存路由组件
1. 作用
让不展示的路由组件保持挂载,不被销毁;即切换回来只是重新激活
2. 实现
<!-- include写需要缓存的组件 应该写组件的组件名即name配置项 -->
<!-- 不写include的话 在此处展示的组件全部缓存 多个组件 :include="[xx,xx]" -->
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
3. 应用场景
如,Home组件可以跳转到News和Message路由组件,News组件内有input输入框,在从News组件切换到Message组件时,News组件被销毁,切换回来时会重新挂载。因此,输入框内的内容就没有了。
4. 两个新的生命周期钩子
1. 作用
路由组件所独有的两个钩子,用于捕获路由组件的激活状态
2. 函数名
- activated在路由组件被激活时触发
- deactivated在路由组件失活时触发
3. 与mounted钩子的区别
activated钩子不受缓存的影响,每次重新切换回某个路由组件都会执行。
mounted钩子在挂载时执行一次,如果没有缓存的话,再次切回,mounted还会执行,从而导致ajax反复获取数据????? 不是说路由改变不向后端发送请求捏??
七、路由守卫
1.作用
在组件加载前或加载后执行方法,可以加判断拦截
2. 类别
- 全局守卫
- 独享守卫
- 组件内守卫
2.1 全局守卫
2.1.1 全局前置路由守卫
const router = new VueRouter({routes:[...]})
// 在index.js创建路由器时,配置全局前置路由守卫
// 在初始化和每一次路由切换之前,都会帮你调用一次这里面的函数
// 这个函数会接收三个参数
router.beforeEach((to, from, next) => {
console.log('@');
console.log('前置', to, from);
// 不应该在前置路由守卫里改标题
// document.title = to.meta.title || '银灰'
// 判断去哪儿
// path和name都可以判断
// meta配置项:路由元信息 可以在里面自定义属性 是否需要鉴权
// 这样就不要一个个判断path/name了
if (to.meta.isAuth) { //是否需要鉴定权限
// 是否放行
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('无权查看')
}
} else { //不需要鉴权
next()
}
})
export defalut router
2.1.2 全局后置路由守卫
const router = new VueRouter({routes:[...]})
// 全局后置路由守卫
// 后置路由守卫是切换后才调用的,没有next,因为已经切换完啦
router.afterEach((to, from) => {
console.log('后置', to, from);
document.title = to.meta.title || '银灰'
})
export default router
2.2 独享守卫
2.2.1 作用
某个路由组件独享的,某个路由的配置项
{
name: 'xinwen',
path: 'news',
component: News,
meta: { isAuth: true, title: '新闻' },
// 独享路由守卫 (可以配合全局路由守卫一起使用)
beforeEnter: (to, from, next) => {
console.log(to, from, next);
if (to.meta.isAuth) {
// 是否放行
if (localStorage.getItem('school') === 'atguigu') {
next()
} else {
alert('学校名不对,无权查看')
}
} else { //不需要鉴权
next()
}
}
2.3 组件内守卫
2.3.1 作用
- 通过路由规则后,进入或离开该组件时被调用
- 不符合路由规则,则不会被调用,和独享守卫的区别所在
- 也可以配合其他守卫使用
2.3.2 实现
export default {
name: "About",
// 通过路由规则,【进入】该组件时被调用
beforeRouteEnter(to, from, next) {
console.log("About-beforeRouterEnter", to, from);
if (to.meta.isAuth) {
// 是否放行
if (localStorage.getItem("school") === "atguigu") {
next();
} else {
alert("学校名不对,无权查看");
}
} else {
next();
}
},
// 通过路由规则,【离开】该组件时被调用
beforeRouteLeave(to, from, next) {
console.log("About-beforeRouterLeave", to, from);
next();
},
};
八、路由的两种工作模式
1. 前情提要
- 对于一个URL来说,#及其后面的内容就是hash值
- hash虽然出现在URL中,但不会包含在 HTTP 请求中,即:hash值不会带给服务器
- 因此改变hash不会重新加载页面,也就不会发起ajax请求???
2. 路由的两种工作模式
- hash模式
- history模式
2.1 hash模式(默认)
- 地址栏中URL永远带着#号,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
2.2 history模式
- 利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法(需要特定浏览器支持)
- 地址干净,美观
- 兼容性和hash模式相比略差
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
3. 如何切换两种模式
在创建路由时,加入mode配置项(不加默认是hash)
mode: 'history',