一、vue强制刷新的方法、组件销毁
前言
在开发过程中,有时候会遇到这么一种情况:
1.切换页面页面没有更新
2.通过动态的赋值,但是dom没有及时更新,能够获取到动态赋的值,但是无法获取到双向绑定的dom节点,
这就需要我们手动进行强制刷新组件,下面这篇文章主要给大家介绍了关于vue组件强制刷新的方案,需要的朋友可以参考下
- 刷新整个页面(最low的,可以借助router机制)
- 使用v-if标记(比较low的)
- provide和inject实现页面刷新
- 使用内置的forceUpdate方法(较好的)
- 使用key-changing优化组件(最好的)
- nextTick配合v-if
location.reload();
this.$rotuer.go(0);存在问题:
1.强制刷新页面,出现短暂的空白闪烁。
2.h5页面在安卓机方法不兼容。
- this.$rotuer.go(0) 安卓、ios都不支持、pc支持
- location.reload() 安卓不支持 、 ios支持、pc支持
vue组件会在什么时候下被销毁?
1.页面关闭
2.路由跳转
3.v-if为false
4.改变key值
1.1 强制全局刷新方法1- location.reload()
重新载入当前文档:location.reload(); 这个方法会重新加载整个页面,包括执行所有的 JavaScript 脚本。
定义和用法:
reload() 方法用于刷新当前文档。
reload() 方法类似于你浏览器上的刷新页面按钮F5。
案例:
点击修改按钮后,重新加载页面,让修改后的结果显示出来。
onSubmit() {
...
update(...).then(response => {
if (response.success) {
this.$message({
message: response.msg,
type: response.success
});
}
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
location.reload()
},
PS:用location.reload()方法是肯定会刷新的。
1.2 强制全局刷新方法2- this.$router.go(0)
经常使用vue的小伙伴看到这个应该很熟悉吧,我们经常用它来实现前进后退,但别忘了它还可以实现自身页面刷新
this.$router.go(0)
对于以上两种方法,虽然都可以实现页面刷新,但页面会刷的白一下,给用户的体验非常不好。利用provide/inject组合方式是我目前觉得最好用的方法,而且可以实现局部刷新。
1.3 强制全局刷新方法3- this.$forceUpdate();
<template>
<div>xxx</div>
<el-button @click="refresh()">强制刷新</el-button>
</template>
<script>
export default {
data() {
return {}
},
methods: {
refresh() {
// forceUpdate只会强制更新页面,不会更新现有的计算属性。
this.$forceUpdate();
}
}
}
</script>
1.4 强制局部刷新方法- provide inject和v-if
通过设置isReload来解决不刷新问题,原理就是通过 v-if 控制组件容器的出现与消失, 达到重新渲染的效果 , 从而实现我们的目的。
(1)在父组件Layout.vue的子组件Content.vue 中定义全局方法reload()
注意:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view v-if="isReload1"/>
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
data() {
return {
isReload1: true
}
},
// 祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
provide() {
return {
reload1: this.reload1,
};
},
methods: {
reload1() {
this.isReload1 = false;
this.$nextTick(() => {
this.isReload1 = true;
});
},
}
}
</script>
<style scoped>
.app-main {
/*58 = navbar */
min-height: calc(100vh - 58px);
position: relative;
overflow: hidden;
}
</style>
在需要引入的子组件中引入
inject: ["reload1"]
然后在子组件调用此方法:
<template>
<div class="page">
<button @click="reloadFun">刷新</button>
</div>
</template>
<script>
import Vue from 'vue';
export default {
inject:['reload'], // 使用 inject 注入 reload 变量
data(){
return{
}
},
methods: {
reloadFun(){
this.reload(); // 直接使用
}
},
}
</script>
这种方法比第一种方法的用户体验好一些。
1.5 使用 v-if(nextTick配合v-if)
<template>
<div v-if="show">xxx</div>
<el-button @click="refresh()">强制刷新</el-button>
</template>
<script>
export default {
data() {
return {
show: true
}
},
methods: {
refresh() {
this.show = false;
// this.$nextTick可实现在DOM 状态更新后,执行传入的方法。
this.$nextTick(() => {
this.show = true;
});
}
}
}
</script>
1.6 使用key-changing优化组件
原理很简单,vue使用key标记组件身份,当key改变时就是释放原始组件,重新加载新的组件。
<template>
<div :key="key">xxx</div>
<el-button @click="refresh()">强制刷新</el-button>
</template>
<script>
export default {
data() {
return {
key: 1
}
},
methods: {
refresh() {
this.key++; // 或者 this.key= new Date().getTime();
}
}
}
</script>
key
的作用与行为
key
的作用:key
是 Vue 用于标识元素或组件唯一性的属性。当key
发生变化时,Vue 会销毁旧的组件实例并创建新的组件实例。- 更改
key
的行为:如果频繁更改key
,Vue 会频繁销毁和创建组件实例,而不是复用已有的实例。
1.7 利用路由进行导航
this.$router.push(this.$route.path);
这种方法不会真正地刷新页面,而是利用 Vue Router 的能力来重新获取当前路由的数据。
这通常比实际刷新页面更高效,因为它避免了完全重载页面带来的开销。
二、如何判断每次进入都会刷新页面
2.1 方法一:使用 Vue 生命周期钩子
Vue 组件提供了几个生命周期钩子,如 beforeCreate
, created
, beforeMount
, mounted
等。
其中 mounted
钩子是在实例被挂载到 DOM 后调用的。
你可以在这个钩子中设置一个标志来标记页面是否已经被初始化。
export default {
name: 'YourComponent',
data() {
return {
isFirstLoad: true,
};
},
mounted() {
if (this.isFirstLoad) {
console.log('页面首次加载');
// 这里可以执行一些只在第一次加载时才需要的操作
this.isFirstLoad = false;
} else {
console.log('页面已经加载过');
}
}
}
这种方法的问题在于,如果用户刷新页面,isFirstLoad
又会被重置为 true
。
因此这种方法只能区分首次加载与之后的任何加载(包括由于路由变化引起的加载)。
2.2 方法二:使用浏览器存储(localStorage/sessionStorage)
如果你想要区分是用户刷新了页面还是直接通过 URL 访问的页面,可以使用 localStorage
或者 sessionStorage
来保存一个标识。
export default {
name: 'YourComponent',
created() {
let isFirstLoad = localStorage.getItem('firstLoad');
if (!isFirstLoad) {
console.log('页面首次加载');
// 执行一些只在第一次加载时需要的操作
localStorage.setItem('firstLoad', 'false');
} else {
console.log('页面已经加载过');
// 如果是刷新页面,也可以在这里做一些处理
}
},
beforeDestroy() {
// 在组件销毁前,清空标识,以便下次访问时正确识别
localStorage.removeItem('firstLoad');
}
}
这种方法可以在用户刷新页面时保留状态,但是当用户清除浏览器缓存或更换设备后,标识就会丢失。
另外,在组件销毁之前记得清理标识,这样下次访问该页面时可以正确地识别为首次加载。
2.3 方法三:使用 Vue Router 的导航守卫
如果你的应用是一个单页面应用并且使用了 Vue Router,那么可以使用全局的前置守卫 beforeEach
来检测用户的动作。
import VueRouter from 'vue-router';
const router = new VueRouter(...);
router.beforeEach((to, from, next) => {
if (to.name === 'YourComponent') {
const isFirstLoad = sessionStorage.getItem('firstLoad');
if (!isFirstLoad) {
console.log('页面首次加载');
sessionStorage.setItem('firstLoad', 'false');
} else {
console.log('页面已经加载过');
}
}
next();
});