问题:当几个页面渲染在同一个路由下,依靠id来改变页面时,页面地址改变了但是页面并没有变(视图没有更新)
问题解析:
虽然地址改变了,但是页面只会创建一次,不会再次去发送请求,setup只会执行一次,导致页面不会刷新
解决方法一:
给路由出口增加 key属性
<RouterView :key="$router.fullPath">
key的作用:判断虚拟dom是否要销毁重建的依据
公式:
render函数(数据) ===> 虚拟dom
render函数1(数据) ===> 虚拟dom1
render函数2(数据) ===> 虚拟dom2
vue会比较虚拟dom1 和 虚拟dom2的区别(diff算法),决定是否要更新页面(更新哪一部分)
key在diff算法工作时,用来比对虚拟dom1 虚拟dom2是都相同,
如果key相同,不更新
如果key不同,就一定要更新
优点:简单粗暴;
缺点:类似v-if销毁重建组件,会有一定的性能损耗;
解决方法二:
通过watch监听路由中id的变化,重新发送请求,因为页面创建时也要发送请求,加上第三个参数immediate:true ,立即执行即可
setup(){
watch(()=>route.params.id,(newVal)=>{
// 发送需要的请求
},{immediate:true})
}
优点:没有销毁重建,从更底层的方式(侦听响应式数据的变化)去切入重发请求
缺点:代码量较多
解决方法三:
使用钩子函数 onBeforeRouteUpdate (只会在路由更改的时候执行)
首次创建的时候依旧要发送一次请求
注意:这里有一个坑点,在这个钩子函数中发送请求时要用它参数中的值去发送请求,(to.params.id)
若还是用之前的参数发请求,它会以上一次的参数发送请求,导致请求错乱
onBeforeRouteUpdate((to)=>{
// 发送需要的请求
})
详细代码如下:
import { ref, onMounted } from 'vue'
import {useRoute, onBeforeRouteUpdate} from 'vue-router
setup(){
const route = useRoute()
const cate = ref({})
const loadCategoryList = (id) => {
// 获取当前数据
findTopCategory(id).then(data => {
cate.value = data.result
})
}
// 页面创建时执行(直接从路由中获取id)
onMounted(() => {
loadCategoryList(route.params.id)
})
// 在路由跳转之后更新之前自动执行
// beforeEach((to,from,next)=>{})
onBeforeRouteUpdate((to) => {
// to指代的是目标路由对象 to拿到最新的路由参数id
// 使用最新id获取数据
loadCategoryList(to.params.id)
})
return { cate }
}
优点:没有销毁重建,逻辑较为直观 缺点:代码量较多