vue 先执行 父组件中mounted 再执行子组件的mounted 的处理【子组件调用父组件的接口回调数据的坑】

首先我们来看下vue 的渲染等执行顺序

//加载渲染过程
父组件 beforeCreate
父组件 created
父组件 beforeMount
子组件 beforeCreate
子组件 created
子组件 beforeMount
子组件 mounted
父组件 mounted
//更新过程
父组件 beforeUpdate
子组件 beforeUpdate
子组件 updated
父组件 updated
//销毁过程
父组件 beforeDestroy
子组件 beforeDestroy
子组件 destroyed
父组件 destroyed

 

 

但是在我们实际开发的的业务中,经常存在先父组件中请求接口,拿到数据再传给子组件进行渲染的情况,由于vue先执行mounted再执行父组件的执行顺序,所以在子组件在渲染时拿不到父组件的接口回调回来的数据,这时可以有以下三种解决方法:

方案一:

1、在父组件请求成功后再初始化渲染子组件,使用用子组件时添加v-if="flag"

2、flag初始化为:false.

3、在请求成功后修改flag为true。

//父组件
<template>
    <div class="world-scroll-table">
      <ScrollTable :dealList="dealList" ref="table"  v-if="flag" />
    </div>
</template>
<script>
import ScrollTable from './components/ScrollTable'
import { getAction } from '@api/manage'
export default {
  components: {
    ScrollTable,
  },
  data() {
    return {
      flag:false,
      dealList:[], 
      url: {
        dealList:'/bitcoin/bigScreen/pendingBtc'//最新交易通告
      },
    }
  },
  mounted() {
    this.initDealList()
    window.parentMounted = this._isMounted//方案3第一步
  },
  methods: {
    /*
     * 初始化最新交易通告数据
     */
    initDealList() {
      getAction(this.url.dealList)
        .then((res) => {
          var arr = [];
          for(let i=0;i<res.length;i++){
            arr.push([res[i].txid, res[i].timeDate, res[i].fee])
          }
          this.dealList = arr
          this.flag =true
        })
        .catch((err) => {
          this.$message.error(err)
        })
    },
  }
//子组件
<template>
  <div class="scroll-table">
    <img src="@/assets/bigScreen/kuang-bg.png" class="scroll-table-bg" />
    <dv-scroll-board :config="config" class="scroll-table-table" />
  </div>
</template>
<script>
export default {
  props: {
    dealList: {
      type: Array,
      default: [],
    },
  },
  data() {
    return {
      
      config: {},
      header: ['交易哈希', '交易时间', '交易费'],
      data: [],
    }
  },
  mounted() {
          this.config = {
          header: this.header,
          data: this.dealList,
          rowNum: 5, // 表行数
          waitTime: 2000, // 轮播时间间隔(ms)
          align: ['center'],
          columnWidth: [50],
          index: true,
          indexHeader: '',
          headerBGC: 'transparent', // 表头背景色
          oddRowBGC: '', // 偶数行背景色
          evenRowBGC: 'rgba(85, 156, 178, 0.1)', // 奇数行背景色
        }
  },
}
</script>
<style lang="less" scoped>
.scroll-table {
  position: relative;

  /deep/.dv-scroll-board .header {
    height: 35px;
  }

  /deep/.scroll-table-table {
    position: absolute;
    top: 44px;
    width: 585px;
    height: 328px;
    padding: 0 10px;
    .header {
      font-size: 16px;
      font-family: Microsoft YaHei;
      font-weight: bold;
      color: #ffffff;
    }

    .row-item {
      font-size: 14px;
      font-family: Microsoft YaHei;
      font-weight: 400;
      color: #bfc3c4;
    }
  }
}
</style>

 方案二:

1、在子组件中使用watch监听,当dealList数据变化(获取到父组件传递过来的数据)时再渲染

//父组件
<template>
    <div class="world-scroll-table">
      <ScrollTable :dealList="dealList" ref="table" />
    </div>
</template>
<script>
import ScrollTable from './components/ScrollTable'
import { getAction } from '@api/manage'
export default {
  components: {
    ScrollTable,
  },
  data() {
    return {
      dealList:[], 
      url: {
        dealList:'/bitcoin/bigScreen/pendingBtc'//最新交易通告
      },
    }
  },
  mounted() {
    this.initDealList()
  },
  methods: {
    /*
     * 初始化最新交易通告数据
     */
    initDealList() {
      getAction(this.url.dealList)
        .then((res) => {
          var arr = [];
          for(let i=0;i<res.length;i++){
            arr.push([res[i].txid, res[i].timeDate, res[i].fee])
          }
          this.dealList = arr
        })
        .catch((err) => {
          this.$message.error(err)
        })
    },
  }
<template>
  <div class="scroll-table">
    <img src="@/assets/bigScreen/kuang-bg.png" class="scroll-table-bg" />
    <dv-scroll-board :config="config" ref="scrollBoard" class="scroll-table-table" />
  </div>
</template>
<script>
export default {
  props: {
    dealList: {
      type: Array,
      default: [],
    },
  },
  data() {
    return {
      config: {},
      header: ['交易哈希', '交易时间', '交易费'],
      data: [],
    }
  },
  mounted() {},
  methods:{
    initTable(){
      this.config = {
          header: this.header,
          data: this.dealList,
          rowNum: 5, // 表行数
          waitTime: 2000, // 轮播时间间隔(ms)
          align: ['center'],
          columnWidth: [50],
          index: true,
          indexHeader: '',
          headerBGC: 'transparent', // 表头背景色
          oddRowBGC: '', // 偶数行背景色
          evenRowBGC: 'rgba(85, 156, 178, 0.1)', // 奇数行背景色
        }
    }
  },
  watch:{
    dealList:{
      deep:true,
      handler:function(){
        this.initTable()
      }
    }
  }
}
</script>

 

方案三:

【思路】 通过打印 this 发现,有一个 _isMounted 属性,表示当前是否挂载完毕(true:挂载完毕,false:没有挂载完成),在父组件挂载前将 _isMounted 存在 window 中,挂载后更新 _isMounted。在子组件 mounted 中添加定时器,根据 _isMounted 判断是否执行初始化方法。

// 父组件
beforeMount() {
    window.parentMounted = this._isMounted    // _isMounted是当前实例mouned()是否执行 此时为false,实际使用时这步可以不要
},
mounted() {
    this.initDealList() //该方法是去请求接口拿到回调数据
    window.parentMounted = this._isMounted    // _isMounted是当前实例mouned()是否执行 此时为true
}
// 子组件
mounted() {
    let pMountedTimer = window.setInterval(() => {
        if (window.parentMounted ) {
            window.clearInterval(pMountedTimer)
            // 下面就可以写子组件想在mounted时执行代码(此时父组件的mounted已经执行完毕)
            this.config = {
                  header: this.header,
                  data: this.dealList,
                  rowNum: 5, // 表行数
                  waitTime: 2000, // 轮播时间间隔(ms)
                  align: ['center'],
                  columnWidth: [50],
                  index: true,
                  indexHeader: '',
                  headerBGC: 'transparent', // 表头背景色
                  oddRowBGC: '', // 偶数行背景色
                  evenRowBGC: 'rgba(85, 156, 178, 0.1)', // 奇数行背景色
            }
        }
    }, 2000)// 经过测试这里子组件的定时器不生效,如果渲染的时候还是子组件还是没有拿到父组件传过来的数据,那么延长这个时间即可,所以推荐方案一、二
} 

 

posted @ 2021-08-16 16:01  逸凨  阅读(6665)  评论(1编辑  收藏  举报