Vue如何实现当前组件重新加载

Vue
697
0
0
2023-01-02

背景

在最近开发一些功能需求的时候,会遇到重新加载当前组件的情况。当父组件发生了数据变化需要,重置按钮,只刷新当前加载的子组件等情况。

本文就来了解下Vue如何实现当前组件重新加载的几种使用方法。

img

解决方案

重新加载整个页面

location. reload()和this.$router.go(0)都可以刷新当前页面的,缺点就是相当于按ctrl+F5 强制刷新,整个页面重新加载,会出现一个瞬间的空白页面,体验不好。

img

父组件代码:

<template> 
  <div id="app"> 
    <Son/> 
    <Button type="primary" @click="reloadPage()">刷新</Button> 
  </div>
</template>
<script>
import Son from '../../views/TestPage/Son'
export default {
  name: 'App',
  components: {
    Son
  },
  provide () {
    return {
      reload: this.reload
    }
  },
  data () {
    return {
      isRouterShow: true
    }
  },
  methods: {
    reloadPage(){
      location. reload();
      this.$router.go(0);
    }
  }
}
</script>

子组件代码:

<template> 
  <div> 
    <div> 
      <h3>子组件</h3> 
    </div> 
  </div>
</template>

<script>


export default {
  name: "son",
  data() {
    return {

    }
  },
  created() {
    this.getList()
  },
  methods: {
    getList(){
      alert("----- getList -----")
    }
  }
}
</script>

v-if可以实现 true (加载)和false(卸载)

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

img

父组件代码:

<template> 
  <div id="app"> 
    <Son v-if="isSonShow"/> 
    <Button type="primary" @click="reloadPage()">刷新</Button> 
    <Button type="primary" @click="hiddenPage()">隐藏</Button> 
  </div>
</template>
<script>
import Son from '../../views/TestPage/Son'
export default {
  name: 'App',
  components: {
    Son
  },
  provide () {
    return {
      reload: this.reload
    }
  },
  data () {
    return {
      isSonShow: false,
      isRouterShow: true
    }
  },
  methods: {
    reloadPage(){
         this.isSonShow = false 
        this.$nextTick(() => {
          this.isSonShow = true
        })        
    },
    hiddenPage(){
      this.isSonShow = false
    }
  }
}
</script>

使用 $forceUpdate

$forceUpdate()迫使vue实例重新(rander)渲染虚拟DOM,注意并不是重新加载组件。

结合vue的生命周期,调用$forceUpdate后只会触发beforeUpdate和updated这两个钩子函数,不会触发其他的钩子函数。

它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

强制刷新: this.$forceUpdate(), 同等效果的:window.location.reload()。

img

父组件代码:

<template> 
  <div id="app"> 
    <Son /> 
    <Button type="primary" @click="reloadPage()">刷新</Button> 
  </div>
</template>
<script>
import Son from '../../views/TestPage/Son'
export default {
  name: 'App',
  components: {
    Son
  },
  provide () {
    return {
      reload: this.reload
    }
  },
  data () {
    return {
      isSonShow: false,
      isRouterShow: true
    }
  },

  updated() {
    console.log("父组件更新了");
  },

  methods: {
    reloadPage(){
      this.$forceUpdate()
    }
  }
}
</script>

使用组件中的 :key

如果需要每次在当前父页面更新时重载某个组件就可以用这个方法,每次组件更新 :key 都会重新取值,而时间戳每次都是不同的,组件发现 :key发生变化就会重新渲染。

img

父组件代码:

<template> 
  <div id="app"> 
    <Button type="primary" @click="clickM">点击indexKey+1导致刷新子组件</Button> 
    <Son ref="child1" :key='indexKey' :childProp='indexKey'/> 
  </div>
</template>
<script>
import Son from '../../views/TestPage/Son'
export default {
  name: 'App',
  components: {
    Son
  },
  provide () {
    return {
      reload: this.reload
    }
  },
  data () {
    return {
      isSonShow: false,
      isRouterShow: true,
      indexKey: 0
    }
  },
  methods: {

    clickM() {
      this.indexKey += 1;
    },

    reloadPage(){
      this.$forceUpdate()
    },
    hiddenPage(){
      this.isSonShow = false
    },
    async reload () {
      this.isRouterShow = false 
      await this.$nextTick()
      this.isRouterShow = true
    }
  },
  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>

父组件中去掉:key='indexKey'

<Son ref="child1"  :childProp='indexKey'/>

img

结语

重新加载整个页面的方法不推荐使用,主要是在体验效果上不好。

$forceUpdate: 不会更新子组件,也不太推荐使用。

v-if通过控制变量的方式来实现重新加载,比较推荐。

使用组件中的 :key的方式相对比较优雅和简单,推荐使用。