[Vue]组件强制刷新/重新渲染
问题描述:
父组件(father)中,通过visible属性来控制子组件(son)的显示与隐藏,如下:
// 父组件father.vue
<template>
<div class="wrap">
<!-- 流程 -->
<son @show="showPopup"></son>
<!-- 弹出框 -->
<div :visible="visible">
<!-- 流程 -->
<son :active.sync="active" @show="showTimeline"></son>
<!-- 时间轴 -->
<div>这是时间轴</div>
</div>
</div>
</template>
- 代码解释:
在父组件中,使用了两次子组件,需求情景如下:
在一流程(称为:流程a)中,有多个环节,以各种不同的图标表示,当点击某一图标时,会出现弹出框,弹出框会再一次显示这一流程(称为:流程a'),用户可以通过点击弹出框中的某一图标查看对应时间轴。
要求:用户可通过在流程a中点击查看对应时间轴,也可在弹出框中查看时间轴(时间轴的出现只在弹出框中)。
showDrawer()方法实现弹出框与时间轴的显示,showTimeline()方法实现时间轴的显示。
visible属性控制弹出层的显示与隐藏,active属性控制流程中环节图标的高亮。@show事件表示子组件son通过show调用父组件father的方法,做到弹出框/时间轴的显示。
// 子组件son.vue
<template>
<div>
<div v-for="(item, index) in stepList" :key="index">
<div @click="show">{{item}}</div>
</x-row>
</div>
</template>
<script>
// js 部分代码
export default {
methods: {
show(item) {
this.$emit("show", item);
}
}
};
</script>
- 代码解释:
子组件中stepList数组中包括流程各环节,通过click事件来调用父组件中的方法。
问题出现:
如上图,点击流程a的第二个图标【吃饭】,图标高亮,出现弹出框,流程a'相同图标【吃饭】高亮,且出现相应的时间轴。接着在流程a'中点击另一图标【做饭 or 洗碗】,会出现相应时间轴,但是:
问题1:流程a'的高亮图标与流程a的不同,换句话说,流程a的高亮图标不会随着流程a'的图标高亮而变化。
TODO:问题1待解决。
继续操作,刷新页面,点开流程a第一个图标【做饭】,弹出流程a',流程a'第一个图标【做饭】高亮,接着在流程a'点击第二个图标【吃饭】高亮且有时间轴,关闭弹窗(流程a'),再打开弹窗(流程a'):
如上图,流程a'的第二个图标【吃饭】高亮,流程a还停留在第一个图标【做饭】高亮,并不是与流程a一致(正常效果应该是:点击流程a的第一个图标【吃饭】,流程a'的第一个图标【吃饭】高亮):
问题2:监听stepList和active数据变化,一切正常,时间轴显示数据正确,只是流程a'的图标高亮显示错误。
问题2根源:其实是子组件没有重新遍历新的stepList数组。
解决方法:流程a'强制刷新/重新渲染。在弹出框的son组件中添加*** :key="timer" ***
// 父组件father.vue
<template>
<div class="wrap">
<!-- 流程 -->
<son @show="showPopup"></son>
<!-- 弹出框 -->
<div :visible="visible">
<!-- 流程 -->
<son :active.sync="active" @show="showTimeline" :key="timer"></son>
<!-- 时间轴 -->
<div>这是时间轴</div>
</div>
</div>
</template>
// js 部分代码
export default {
data() {
return {
visible: false,
timer: ""
};
},
methods: {
showPopup(item) {
this.visible = true;
this.timer = new Date().getTime(); // 时间戳做子组件son的key
this.showTimeline(item); // 获取时间轴数据
}
}
};
</script>
谈谈子组件强制刷新/重新渲染的4种方法
v-if
简单粗暴的方法。通过 v-if 控制子组件的显隐(删除旧组件,创建新组件,直接操作 DOM 元素)。
操作:当需要强制更新子组件时,将变量置为 false , 然后在 $nextTrack() 中将变量置为 true。
注意:
1、必须要在 nextTick 以后才能更改,否则会看不到效果。
在 Vue 中,DOM 的更新周期即为一个 tick , 在同一个 tick 内 Vue 会搜集变化,然后在 tick 的最后会根据变化的值去更新节点,如果我们不等到 next tick , 直接更新变量的值,不会触发节点的更新。
2、当我们重新渲染的时候,Vue 将会创建一个新的组件。Vue 销毁之前的,重新创建新的,意味着新的组件会重新走一遍生命周期。
key
最推荐。通过动态改变 key 值重新渲染。
如果 key 保持不变,则不会更改组件;但当 key 发生更改时,Vue 会删除旧组件并创建新组件,它将重新初始化自身并“重置”其状态。
原理:vue 在渲染 DOM 时,采用的 diff 算法,而 diff 算法则是根据 key 的值判断 DOM 节点是否需要重新渲染。
forceUpdate
强制更新页面。
reloading 最差的方法,不要用。