vue[强制刷新组件之$forceupdate、v-if、key属性三种方式的适用]

有时候我们会遇到一些问题,例如:弹出框在填写完毕后隐藏,然后再次点击打开的时候内容确还是原来的,此时需要刷新组件来操作。或者有些时候我们需要强制触发组件的刷新以便于让整个组件的生命周期得以重新执行。又或者某些数据明明改变了,但是确没有刷新视图。
本例探讨强制刷新组件的几种操作,每种操作都有其适用场所,各有优缺点。

总结

  1. $ forceupdate()仅针对当前组件以及其插槽相关子组件。
    作用:例如当data中的某个内容进行了改变,但是页面没有进行实时的刷新,而我又通过打印能确定数据确实改变了,因此可以使用$ forceupdate()来迫使当前组件刷新。
    常见示例代码:
// dataArray:[]
// carList:[]
for(var i=0; i<this.dataArray.length; i++){ 
  let flag = false; //默认没有选中
  for(var j=0; j<this.carList.length; j++){ //检测某个数组选项是否已中过
	  if(this.dataArray.code == this.carList[j].name){
	   flag = true;
	   break;
	  }
  }
  // 给数组的每个项的disabled都赋值要么是true,要么为false
  this.dataArray[i].disabled = flag;
 }
}
// 这种情况下有可能会导致代码执行完毕数据确实改变了,但是页面没刷新的情况。
// 因此需要下面的内容
this.$forceupdate();
  1. v-if通过变量控制的形式,可以触发 被控制的组件 beforeCreate、created、beforeMount、mounted、beforeDestroy、destroyed 这6个生命周期,但是由于v-if指令的原因,会导致其控制的内容会发生显示与隐藏操作。虽然可以达到刷新的效果,但是把其当作刷新这个功能,在项目中还是比较少见的。
  2. 通过key属性来进行刷新操作,在web中的效果是最理想的,因为页面根本感觉不到组件的销毁与创建过程,但是确实满足了组件的刷新功能。
    操作方式:在data中定义某个变量,然后将该变量放置在组件的key属性中,要实现该组件刷新时,只需改变变量的值即可。
<template>
    <child ref="child1" :key='indexKey'></child>
</template>
<script>
import child from "./child";
export default {
 components: { child },
 data() {
    return {
      indexKey: 0  // 只需要通过操作如点击事件改变这个值,child子组件就会刷新,而且视觉上不会有变化
    };
  },
 }
</script>
注意:当key值改变的时候,child子组件实际上经历了新的child的创建过程以及旧的child的销毁过程

示例探究

第一种方式:使用 $ forceupdate()

迫使vue组件重新渲染,实际上指的是强制重启render函数。即调用该方法后 只会触发beforeUpdate、updated 这两个生命周期,而且只会影响当前组件以及其插槽内容
在这里插入图片描述
在这里插入图片描述

最常见的一种问题:就是在v-for循环或者某个操作中对data中的内容进行增加、修改、或者删除操作,data中的数据确实改变了,而且打印的内容也改变了,但是页面却没有刷新达到理想效果,这里则可以使用this.$ forceupdate()。
问题诞生的本质是vue虽然是响应式的.但受到javascript的限制,Vue不能检测到对象属性的添加或删除,因为vue在初始化实列时将属性转为getter/setter,所以属性必须在data对象上才能让vue转换它
调用$ forceupdate()就能够让页面重启render函数,即将数据的改变重新进行渲染,就感觉手动刷新页面一样,但是只会触发两个生命周期beforeUpdate和updated

该问题的另一种解决方式可以使用Vue.$set()的方法替代直接取值赋值的方式进行数据上的设置与改变,但是与本例无关,因此仅做说明。

第二种方式:使用 v-if

使用v-if加上变量的形式来控制组件的加载与销毁,好处在于能够直接触发组件的完整生命周期
使用v-if的好处在于可以在父组件中通过某个变量来控制子组件的渲染,打开的时候子组件会触发beforeCreate、created、beforeMount、mounted四个生命周期,关闭的时候子组件会触发beforeDestroy、destroyed两个生命周期,因此在某些操作中如果需要通过某个变量的内容来对子组件进行生命周期的刷新,即可用v-if来进行显隐操作
示例:
父组件代码

<template>
  <div class="login-box">
    <button @click="clickM">点击打开子组件</button>
    <button @click="clickC">点击关闭子组件</button>
    <child1 ref="child1" v-if="mgs"></child1>
  </div>
</template>

<script>
import child1 from "./child1";
export default {
  components: { child1 },
  data() {
    return {
      mgs: false
    };
  },
  methods: {
    clickM() {
      this.mgs = true;
    },
    clickC(){
      this.mgs = false;
    }
  },
  beforeCreate() {
    console.log("父组件创建前");
  },
  created() {
    console.log("父组件创建后");
  },
  beforeMount() {
    console.log("父组件挂载前");
  },
  mounted() {
    console.log("父组件挂载后");
  },
  beforeUpdate() {
    console.log("父组件刷新前");
  },
  updated() {
    console.log("父组件刷新后");
  },
  beforeDestroy() {
    console.log("父组件销毁前");
  },
  destroyed() {
    console.log("父组件销毁后");
  }
};
</script>

子组件代码

<template>
  <div class="child1">这是子组件</div>
</template>

<script>
export default {
  beforeCreate() {
    console.log("子组件child1创建前");
  },
  created() {
    console.log("子组件child1创建后");
  },
  beforeMount(){
    console.log("子组件child1挂载前");
  },
  mounted(){
    console.log("子组件child1挂载后");
  },
  beforeUpdate() {
    console.log("子组件child1刷新前");
  },
  updated() {
    console.log("子组件child1刷新后");
  },
  beforeDestroy(){
    console.log('子组件child1销毁前');
  },
  destroyed(){
    console.log('子组件child1销毁后');
  }
};
</script>

执行步骤为:进入页面-点击打开子组件-点击关闭子组件。效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第三种方式:使用 key 属性

key属性在vue中见的最多的地方就是在v-for循环的时候必须加上key=xx这个唯一的标志。而这就是体现了key这个属性功能的一种比较常见的场景。
key的作用通俗来讲就是给这个子组件或者元素标签加上一个记号,方便vue根据记号对子组件或者元素标签做排查。一旦某个加上记号的子组件或者元素标签其上的记号进行了改变,vue就会对其做出一些刷新相关的操作。
示例:
父组件代码

<template>
  <div class="login-box">
    <button @click="clickM">点击indexKey+1导致刷新子组件</button>
    <child1 ref="child1" :key='indexKey' :childProp='indexKey'>
    </child1>
  </div>
</template>

<script>
import child1 from "./child1";
export default {
  components: { child1 },
  data() {
    return {
      indexKey: 0
    };
  },
  methods: {
    clickM() {
      this.indexKey += 1;
    }
  },
  beforeCreate() {
    console.log("父组件创建前");
  },
  created() {
    console.log("父组件创建后");
  },
  beforeMount() {
    console.log("父组件挂载前");
  },
  mounted() {
    console.log("父组件挂载后");
  },
  beforeUpdate() {
    console.log("父组件刷新前");
  },
  updated() {
    console.log("父组件刷新后");
  },
  beforeDestroy() {
    console.log("父组件销毁前");
  },
  destroyed() {
    console.log("父组件销毁后");
  }
};
</script>

子组件代码

<template>
  <div class="child1">这是子组件{{childProp}}</div>
</template>

<script>
export default {
  props:['childProp'],
  beforeCreate() {
    console.log("子组件child1创建前");
  },
  created() {
    console.log("子组件child1创建后",this.childProp);
  },
  beforeMount(){
    console.log("子组件child1挂载前",this.childProp);
  },
  mounted(){
    console.log("子组件child1挂载后",this.childProp);
  },
  beforeUpdate() {
    console.log("子组件child1刷新前",this.childProp);
  },
  updated() {
    console.log("子组件child1刷新后",this.childProp);
  },
  beforeDestroy(){
    console.log('子组件child1销毁前',this.childProp);
  },
  destroyed(){
    console.log('子组件child1销毁后',this.childProp);
  }
};
</script>

还没点击,仅仅加载创建过程效果
在这里插入图片描述
点击按钮
在这里插入图片描述
从图中可以看出子组件进行了销毁与创建的过程。

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值