在Vue里父组件给子组件间使用props方式传递数据,但是希望父组件的一个状态值改变然后子组件也能监听到这个数据的改变来更新子组件的状态。
一、生命周期函数——通过props中的传递过来的父组件参数让子组件dom发生变化
1、问题引入
- 一开始遇到把值从父组件绑定传值到子组件,子组件(举例简化了一下):
<template>
<div class="contain_div contain_border">
<el-row
v-if="baseData.rentName"
type="flex"
justify="space-around"
>
<el-col
:span="7"
class="contain_sub"
>
<h3 class="mainTitle">贡献租户</h3>
<p class="subTitle">{{baseData.rentName }}</p>
</el-col>
<el-col
:span="7"
class="contain_sub"
>
<h5 class="mainTitle">标题最新版本</h5>
<p class="subTitle">
{{baseData.name}}
{{baseData.newVersion}}
通用版
</p>
</el-col>
<el-col
:span="7"
class="contain_sub"
>
<h5 class="mainTitle">标题关注度</h5>
<div>
<i
class="iconfont icon-xin xin"
v-if="follow == false"
></i>
<i
class="iconfont icon-aixin aixin"
v-if="follow == true"
></i>
<span class="followNum">
-关注( {{followNum}}人气)
</span>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
props: {
baseData: {
type: Object,
default() {
return {
rentName: "", //租户名称
rent: "", //租户
name: "", //模块名称
newVersion: "", //最新版本
id: "" //id
};
}
}
},
data() {
return {
follow: false, //判断显示 空心/爱心
followNum: 0 //关注人数
};
},
methods: {
/* 查询是否已关注 */
checkFollow(id) {},
/* 查询关注数 */
queryFollowNum(id) {}
},
beforeUpdate() {
console.log('基本信息-数据改变前');
this.queryFollowNum(this.baseData.id);
this.checkFollow(this.baseData.id);
}
};
</script>
其中baseData
即为父组件属性绑定传过来的数据。这里的html页面有直接引用父页面数据,可以通过父页面数据使页面发生改变。
结果,正常执行。此子组件刚加载,即会执行beforeUpdate()
。我以为是props
中数据发生改变,即会触发beforeUpdate()
。
- 事实并非如此。因为后面又遇到了这个问题,用了类似的方法。
<template>
<div class="contain_div">
<div v-if="ifDrawData">
<div class='transferRelation'></div>
</div>
<div
class="system_name"
v-if="!ifDrawData">暂时没有数据</div>
</div>
</template>
<script>
export default {
props: {
relyData: {
type: Object,
default() {
return {
data: [],
link: []
};
}
}
},
data() {
return {
ifDrawData: false //显示组件/提示暂无数据
};
},
beforeUpdate() {
console.log("调用关系-数据改变前");
//判断显示
if (this.relyData.data.length == 0) {
this.ifDrawData = false;
} else {
this.ifDrawData = true;
}
//TODO 初始化echart图表
}
};
</script>
其中relyData
即为父组件属性绑定传过来的数据。这里的html页面没有直接引用父页面数据,而是想通过父页面传值过来后,props
中数据接收值发生了改变,然后触发beforeUpdate()
方法来进行页面显示判断,然后echart初始化表格。
结果,beforeUpdate()
方法根本就没被触发,说明props
中数据发生改变根本不会触发beforeUpdate
生命周期。
2、生命周期函数的测试
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h3 id="h3">{{msg}}</h3>
<input type="button" value="修改" @click="msg='no'" />
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: 'ok'
},
created() {
console.log('created');
},
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
}
});
</script>
</body>
</html>
进行了一下简单的生命周期测试,正常加载一个组件,beforeUpdate
不会触发。
而通过按钮触发修改data
中数据,或者直接在mounted()
中改变data
中msg
的值,都会触发beforeUpdate()
。
那为什么第一个例子的子组件中,父组件传值过来后,data数据也没发生改变,却触发了beforeUpdate()
?
3、结论
对比了一下是,第一个例子的子组件中,虽然页面加载时虽然data没有改变,但是页面发生改变了(通过父组件传过来的值加载了部分内容),即 v 层发生了变化,相对的就触发了beforeUpdate()
。
所以只要修改一下第二个例子的子组件,让他的页面也会因为父组件传值而发生变化,即可实现传之后触发beforeUpdate()
。
<div v-if="relyData.data!=undefined && relyData.data.length>0?true:false">
<div class='transferRelation'></div>
</div>
二、watch监听props参数
说句实话,上面想的太复杂了,其实只要watch
监听 props父组件传递过来的参数变化,不就可以直接执行父组件参数改变需要执行的逻辑内容了么。(最终代码)
<template>
<div class="contain_div">
<div v-if="ifDrawData">
<div
class='transferRelation'
ref="transferRelation"
></div>
</div>
<div
class="system_name"
v-if="!ifDrawData"
>暂时没有数据</div>
</div>
</template>
<script>
export default {
props: {
relyData: {
type: Object,
default() {
return {
data: [],
link: []
};
}
}
},
data() {
return {
ifDrawData: false
};
},
watch: {
relyData(newVal, oldVal) {
const _this = this;
const param = newVal;
//判断显示
if (param.data.length == 0) {
_this.ifDrawData = false;
} else {
_this.ifDrawData = true;
}
//初始化图表
this.$nextTick(function() {
console.log(_this.$refs.transferRelation);
//...
});
}
}
};
</script>