首先我们来看下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)// 经过测试这里子组件的定时器不生效,如果渲染的时候还是子组件还是没有拿到父组件传过来的数据,那么延长这个时间即可,所以推荐方案一、二
}