【面试 - 遇到的问题】Vue 里 router-view 使用 key + 关闭页面后重新打开页面-获取的数据赋值到旧组件问题(钩子执行顺序)
目录
- 【1】问题描述
- 【2】问题排查前 - 页面渲染、tag 页签渲染 逻辑梳理
- 页面渲染
- 【借用别人的描述】`<router-view :key="key" />`
- 1. 不设置key 属性
- 2. 设置 key 属性值为 $route.path
- /page/1 => /page/2
- /page?id=1 => /page?id=2,
- 3. 设置 key 属性值为 $route.fullPath
- /page/1 => /page/2
- /page?id=1 => /page?id=2
- tag 页签渲染
- 【3】问题排查
- 【4】解决
【1】问题描述
- 首次打开页面,弹框中有数据
- 点击 tag 页签关闭当前页面
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6056d67fceb249b983066dc077dea36e.png- 再次打开弹框,数据不展示
【2】问题排查前 - 页面渲染、tag 页签渲染 逻辑梳理
页面渲染
<keep-alive>
<router-view :key="key" />
</keep-alive>
- key 作为路由页面唯一标识,这里
key
为页面fullPath 拼接当前时间戳
,拼接时间戳以确保唯一性,避免不同页面 fullPath 一致
【借用别人的描述】<router-view :key="key" />
https://blog.51cto.com/knifeedge/5627137
- Vue 会
复用相同组件
,对于路由有多个子路由
来说,当在子路由来回切换
时,会导致页面不刷新
的问题,因为不再执行 created 和 mounted 这些钩子函数。<router-view :key=“key“/>
中的key
即可解决这个问题。
- 官网里边有一句:Vue 为你提供了一种方式来表达
“这两个元素是完全独立的,不要复用它们”
。只需添加一个具有唯一值的 key attribute 即可- 缺点:加了路由的key值,Vue就会认为这不是同一个组件,update的时候会删除这个组件再重新加载一个新的组件,有严重的性能问题。比如:
- 在后台系统中,点击侧导航菜单子菜单时,设置了:key="$route.path"会导致菜单关闭又打开,视觉效果不好。且如果新的组件未加载完成时获取数据,则会导致新加载的组件内没有得到数据赋值。 ------ 最后这句和本文章所描述问题有关
代码示例
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="key" />
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
key() {
return this.$route.fullPath
}
}
}
</script>
1. 不设置key 属性
Vue 会复用相同组件, 即: /page/1 => /page/2 或者 /page?id=1 => /page?id=2 这类链接跳转时, 不执行created, mounted之类的钩子, 这时候你需要在路由组件中添加beforeRouteUpdate钩子来执行相关方法拉去数据
相关钩子函数为: beforeRouteUpdate
2. 设置 key 属性值为 $route.path
/page/1 => /page/2
由于这两个路由的$route.path不一样, 所以组件被强制不复用, 相关钩子加载顺序为: beforeRouteUpdate => created => mounted
/page?id=1 => /page?id=2,
由于这两个路由的$route.path一样, 所以和没设置 key 属性一样, 会复用组件, 相关钩子加载顺序为: beforeRouteUpdate
3. 设置 key 属性值为 $route.fullPath
/page/1 => /page/2
由于这两个路由的$route.fullPath不一样, 所以组件被强制不复用, 相关钩子加载顺序为: beforeRouteUpdate => created => mounted
/page?id=1 => /page?id=2
由于这两个路由的$route.fullPath不一样, 所以组件被强制不复用, 相关钩子加载顺序为: beforeRouteUpdate => created => mounted
tag 页签渲染
项目中每访问一个页面就将页面路由信息保存在
visitedViews
数据中,tag 页签
就是 通过visitedViews
数据,使用router-link
来渲染,从而实现点击tag 页签
页面路由跳转的效果。
【3】问题排查
上图
紫色框
为问题描述1
中页面组件,红色框
为问题描述3
中页面组件,经过问题描述2
后,问题描述1
的组件不会被复用(因为<router-view :key="key" />
有key
),再次进入页面时,产生了一个新的页面组件,也就是红色框
【问题排查过程】
- 仔细排查代码发现 →
问题描述
中页面未展示的数据获取
是在beforeRouteEnter
中进行的,此时还未产生新的组件
(红色框
的组件)→ 所以获取到的数据其实赋值给了旧的不被复用组件
中(紫色框
的组件) → 导致红色组件加载渲染完毕后,beforeRouteEnter
中获取的数据并未正确展示展示。- 新旧组件 => 两个组件其实
展示的页面是一个
,只不过因为<router-view :key="key" />
中 有key
所以导致当前页面第一次被关掉
之后在打开的时候 key 中拼接的 时间戳 与第一次打开的组件key中的时间戳不一致
,所以回产生一个新的组件
,而不会复用旧组件
。
【4】解决
beforeRouteEnter
中获取数据 改为 在mounted
钩子中获取数据,mounted
是页面渲染完成后调用的钩子,也就是新组件此时已加载完毕,此时获取数据并进行赋值操作都是在新组件中进行。