Vue2路由知识大杂烩, 一下给你全整明白(上)
https://blog.csdn.net/weixin_48524561/article/details/125567465
Vue2路由知识大杂烩, 一下给你全整明白(下)https://blog.csdn.net/weixin_48524561/article/details/125636588
6. 路由的props配置:
它的作用就是在路由匹配规则所匹配的组件接收参数的时候更加简单, 便利. 例如:
现在有一个问题, 传递的值有6个, 我们需要在模板内{{ $route.query/params.xxx }}使用6次. 这样模板内的代码是不是冗余了.
或者说我们使用计算属性, 我只能说更加冗余
这样, 当需要传递的参数很多的话, 我们就可以使用到一个全新的配置项props.
在父向子传值的时候, 我们是不是也涉及到了props属性, 也就是说谁需要我们不是就给谁配置; 路由的props属性也是同理, 谁接收参数我们就上哪配置去. 它一共有三种方法:
- 第一种写法
对象的形式, 该对象的所有键值对都会以props的形式传递给需要接收的组件.
// 定义规则
{
path: 'four',
name: 'FourCom',
component: () => import('@/pages/Four.vue'),
children: [
{
// params传参需要对路由匹配规则进行配置一下
path: 'fourDetail/:id/:name',
name: 'FourDetail',
component: () => import('@/pages/FourDetail.vue'),
// props第一种写法, 对象
props: {
id: 1,
name: '大帅'
}
}
]
}
// 跳转的a连接
<template>
<div>
<h3>我是第四个页面</h3>
<router-link :to="{name: 'FourDetail'}">第四个页面的详情页</router-link>
<router-view></router-view>
</div>
</template>
// 匹配的组件
<template>
<div>
<h3>我是第四个页面的详情数据</h3>
<div>id: {{ id }}</div>
<div>name: {{ name }}</div>
</div>
</template>
<script>
export default {
name: 'FourDetail',
props: ['id', 'name']
}
</script>
- 第二种写法
布尔值的形式, 如果布尔值为真; 就会将所有的params参数, 以props的显示传递给所需要的组件. 注意值服务于params传参, query参数是没有用的.
// 定义规则
{
path: 'four',
name: 'FourCom',
component: () => import('@/pages/Four.vue'),
children: [
{
// params传参需要对路由匹配规则进行配置一下
path: 'fourDetail/:id/:name',
name: 'FourDetail',
component: () => import('@/pages/FourDetail.vue'),
// 第二中写法, 布尔值
props: true
}
]
}
// 跳转的a连接
<template>
<div>
<h3>我是第四个页面</h3>
<router-link :to="{
name: 'FourDetail',
params: {
id: 1,
name: '大帅'
}
}">第四个页面的详情页</router-link>
<router-view></router-view>
</div>
</template>
// 匹配的组件
<template>
<div>
<h3>我是第四个页面的详情数据</h3>
<div>id: {{ id }}</div>
<div>name: {{ name }}</div>
</div>
</template>
<script>
export default {
name: 'FourDetail',
props: ['id', 'name']
}
</script>
- 第三种写法
函数形式, Vue已经帮我们做好了, 它有一个形参就是$route. params参数和query都受用
// 定义规则
{
path: 'four',
name: 'FourCom',
component: () => import('@/pages/Four.vue'),
children: [
{
// params传参需要对路由匹配规则进行配置一下
path: 'fourDetail/:id/:name',
name: 'FourDetail',
component: () => import('@/pages/FourDetail.vue'),
// 第三种写法, 函数
props ({ params }) { // 还可以在对params进行结构{query:{id, name}}
return { id: params.id, name: params.name }
}
}
]
}
// 跳转的a连接
<template>
<div>
<h3>我是第四个页面</h3>
<router-link :to="{
name: 'FourDetail',
params: {
id: 1,
name: '大帅'
}
}">第四个页面的详情页</router-link>
<router-view></router-view>
</div>
</template>
// 匹配的组件
<template>
<div>
<h3>我是第四个页面的详情数据</h3>
<div>id: {{ id }}</div>
<div>name: {{ name }}</div>
</div>
</template>
<script>
export default {
name: 'FourDetail',
props: ['id', 'name']
}
</script>
7. 编程式路由导航:
前面要进行路由跳转的话都必须使用到router-link组件, 那么如果不用这个组件我们就不能跳转了吗?
答案是不, 我们还可以使用编程式导航, 并且我们将router-link做跳转的方法叫声明式导航.
- 再来想一个问题, router-link可以进行路由跳转, 为什么还需要编程式导航了?
因为router-link最后会被解析成a标签, 有时候我们不使用a标签跳转, 拿按钮进行跳转怎么办; 延时跳转怎么做到, 所以就需要编程式导航, 给按钮添加点击事件进行跳转.
this.$router.push( ) 可以不参数,根据传的值自动匹配是path还是name
因为使用path会自动忽略params ,所以会出现两种组合
name+params 方式传参
A页面传参
this.$router.push({
name: 'xxx', // 跳转的路由
params: {
id: id // 发送的参数
}
})
.$router.push({
name: 'xxx', // 跳转的路由
params: {
id: id // 发送的参数
}
})
B页面接收传参
this.$router.params.id
path+query 方式传参
A页面传参
this.$router.push({
path: '/xxx', // 跳转的路由
query: {
id: id // 发送的参数
}
})
.$router.push({
path: '/xxx', // 跳转的路由
query: {
id: id // 发送的参数
}
})
B页面接参
this.$route.query.id
params 和query 方式传参的区别
-
写法上不同
-
地址栏不同
-
刷新方式不同
8. 缓存路由组件:
当组件被切换后, 组件就会被销毁; 但是有些页面不允许让先前的组件销毁, 比如: 让用户填写信息, 用户填完上一页信息, 切换到下一页去; 但是发现上一页信息填错了, 在返回去了信息没了, 用户体验不好.
作用就是让不展示的组件, 保持缓存, 不被销毁.
想让组件切换的时候不被销毁, 就需要keep-alive这个组件, 其中有一个include属性, 指定哪个组件被缓存, 就在include属性里面写哪个组件名.
如果不写include属性, 那么keep-alive组件包含的所有组件都会被缓存.
不写include属性:
<template>
<div id="app">
<nav>
<router-link to="/new">new</router-link> |
<router-link to="/message">message</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
</nav>
</div>
</template>
写了include属性:
<template>
<div id="app">
<nav>
<router-link to="/new">new</router-link> |
<router-link to="/message">message</router-link>
<keep-alive include="NewCom">
<router-view></router-view>
</keep-alive>
</nav>
</div>
</template>
注意, include中填写的是需要缓存的组件名, 和路由组件中的name属性无关. 如果要指定缓存多个可以使用:include="[ 'xxx', 'xxx' ]"
9. keep-alive新增的两个钩子函数:
activated(激活)和deactived(失活), 作用就是用于捕获路由组件激活的状态.
点击那个组件就让他激活, 离开就失活
<template>
<div>
<h3>new组件</h3>
<div><input type="text"></div>
<div><input type="text"></div>
<div><input type="text"></div>
</div>
</template>
<script>
export default {
name: 'NewCom',
activated () {
console.log('new组件激活了')
},
deactivated () {
console.log('new组件失活了')
}
}
</script>
10. 全局路由前置守卫(beforeEach):
古代君王身边都会有一群人就是御前侍卫就是为了保护君王的安全, 那么这里的路由守卫和他干的事是一样的, 保护的是路由的安全.
路由还有安全? 是的路由有安全, 路由守卫就是确保安全的进行路由的跳转, 简单举个栗子:
手机掌上银行, 你没有登录, 我可以让你进入首页吗, 查看金额吗?
router.beforeEach((to, from, next) => {
})
- before的意思就是在什么之前, Each的意思就是每一个, 每一次; 简单理解就是路由在每一次切换之前都会router都会调用这个api. 初始化的时候也会被执行一次
- 其中有三个形参, to: 想要去哪, from: 来自哪, next: 是否需要放行, 它是一个函数
router.beforeEach((to, from, next) => {
if (to.path === '/one/three') {
if (localStorage.getItem('token') === 'luckly') {
next()
console.log(to, from)
}
} else {
next()
}
})
我们现在从"/one", 路径跳转到"/one/three"路径去, 我们打印to和from看看
现在我们来看看if条件, 如果你想去"/one/three"这个地方且localStorage的条件符合才让跳转, 否则不让你跳转. 如果不是正常放行.
12. meta配置项:
我们将meta称之为路由的元信息, 这是为我们提供操作的空间, 我们自定义配置什么我们都可以往里面写.
上述的全局路由前置守卫, 我们还可以这样, 来上代码:
// 配置项
path: 'four',
name: 'FourCom',
component: () => import('@/pages/Four.vue'),
meta: { isAuth: true },
router.beforeEach((to, from, next) => {
// 现在我们判断需要当前跳转路由是否需要权限验证
if (to.meta.isAuth) {
if (localStorage.getItem('token') === 'luckly') {
next()
console.log(to, from)
}
} else {
next()
}
})
13. 全局路由后置守卫(afterEach):
配置项和前置守卫都是一样的, 区别就在于; 它是路由跳转之后执行(初始化会被调用一次).
但是是没有next的, 人都已经进来了, 我还要验证你的信息还有什么用咧?
router.afterEach((to, from) => {
})
它用的少, 但是还是有点场景的; 比如, 路由跳转之后, 我将页面标题切换一下, 来上代码:
注意要配合meta哦!
routes: [
{
path: '/one',
name: 'OneCom',
component: () => import('@/pages/One.vue'),
meta: { title: '第一个页面' },
children: [
{
path: 'three',
name: 'ThreeCom',
meta: { title: '第三个页面' },
component: () => import('@/pages/Three.vue'),
children: [
{
path: 'threeDetail',
name: 'ThreeDetail',
meta: { title: '第三个详情页面' },
component: () => import('@/pages/ThreeDetail')
}
]
},
{
path: 'four',
name: 'FourCom',
component: () => import('@/pages/Four.vue'),
meta: { isAuth: true, title: '第四个页面' },
children: [
{
// params传参需要对路由匹配规则进行配置一下
path: 'fourDetail/:id/:name',
name: 'FourDetail',
meta: { title: '第四个的详情页面' },
component: () => import('@/pages/FourDetail.vue'),
props ({ params }) {
return { id: params.id, name: params.name }
}
}
]
}
]
}
]
router.afterEach((to, from) => {
document.title = to.meta.title || '大帅'
})
再来一个场景, 跳转之前开启加载的进度条, 跳转完毕之后关闭加载进度条
import router from '@/router'
import store from '@/store'
import NProgress from 'nprogress' // 引入一份进度条插件
import 'nprogress/nprogress.css' // 引入进度条样式
const whileList = ['/login', '/404']
router.beforeEach(async(to, from, next) => {
NProgress.start()
const token = store.getters.token
if (token) {
if (to.path === '/login') {
next('/')
NProgress.done()
} else {
if (!store.state.user.userInfo.userId) {
// 没有id表示当前用户资料没有获取过, 就获取一次
await store.dispatch('user/getUserInfo')
}
next()
}
} else {
if (whileList.includes(to.path)) {
next()
} else {
next('/login')
NProgress.done()
}
}
})
router.afterEach((to, from, next) => {
NProgress.done()
})