今天,在做项目期间,遇到了一个问题。
场景如下:在父组件中,引入了两个子组件,两个组件都是自己手工根据需求封装的,分别是<Selector>组件和<DatePicker>组件。Selector组件主要用于条件的筛选,DatePicker主要用于日期的选择。组件之间传值,毕竟传递的属性比较多,所以选择了通过对象Object的形式传递的。场景中,一个父组件包含两个子组件,两个子组件之间是兄弟关系。
<Selector>组件有三个选项:(id=0)日、(id=1)周、(id=2)月。当选择日时,<DatePicker>组件需要展现"年月日"格式筛选,当选择周时,组件需要展现 xxxx 年 xxx周 两列的筛选,当选择月时,组件需要"年月"的筛选。
<Selector>组件,可以通过this.$emit("result",data);的形式将数据由子组件传递给父组件,然后在父组件中通过@result 来接收。如果选择了"日",然后将id=0实时传给DatePicker组件,<DatePicker>子组件根据父组件传递的id来实时的变化<DatePicker>中的具体选项。
具体:就是如下图这个效果
鼓捣了半天。发现子组件还是无法接收到父组件传递给它的值。最后想到了Vuex,但是这本就是个小功能,没有必要用到Vuex。
父组件结构如下(部分代码):
<template>
<div>
<div class="date">
<!-- 类型 -->
<Selector :params="typeSelect" @result="getType"></Selector>
<!-- 日期 -->
<DatePicker :params="dateSelect" @result="getDate"></DatePicker>
</div>
</div>
</template>
<script>
import Selector from '@/components/common/Selector';
import DatePicker from '@/components/common/DatePicker';
export default {
data(){
return {
//1.如下是"类型"组件,数据需要通过父组件传递给子组件
typeSelect:{
id:'typePicker',
defaultSelect:0,
defaultTip:'日',
resultData:[{index:'0',value:'0',text:'日'},{index:'1',value:'1',text:'周'},{index:'2',value:'2',text:'月'}],
allSelectId:0,
allSelectTip:'日',
isHasName:true,
name:'类型'
},
//2.如下是"日期"筛选组件,数据需要通过父组件传递给子组件
dateSelect:{
id:'datePicker',
dateType:'date',
isHasName:true,
name:'时间'
}
}
},
components:{Selector,DatePicker},
methods:{
getType(data){
this.typeValue = data[0].value;
//同步传值给子组件(前提:dateSelect对象声明了个receiveType属性,属于修改属性范畴)
this.dateSelect.receiveType = this.typeValue
//同步传值给子组件(前提:dateSelect对象中没有receiveType属性,属于新增属性范畴)
this.$set(this.dateSelect,"receiveType",this.typeValue);
//如上两种二选一!!!!!!!!
},
getDate(data){
if(this.typeValue == 0){
this.dateValue = data.y.value + data.m.value + data.d.value;
}else if(this.typeValue == 1){
this.dateValue = data[1].value;
}else if(this.typeValue == 2){
this.dateValue = data.y.value+data.m.value;
}
}
},
mounted() {
},
}
</script>
思路:在定义dateSelect对象时,声明一个receiveType属性,默认为空(1、声明后,则对该属性进行修改即可 2、不声明也可以,则是对该对象进行添加属性,区别:一个修改属性,一个添加属性)。因为Vue视图是基于数据驱动来实现的,我们通过getType方法获取"日周月"类型返回值,然后实时修改dateSelect对象信息,子组件DatePicker便可以根据传递的类型实时来变化
实现:①可以在子组件DatePicker中,使用watch来实时监听数据的变化
//1.针对属性存在,默认为空情况,通过如下对数据修改
this.dateSelect.receiveType = this.typeValue
//子组件watch(子组件接收父组件传递过来的参数,名为params)
watch{
params(newValue,oldValue){
//子组件无法监听到变化
},
receiveType(newValue,oldValue){
//子组件无法监听到变化
}
}
//1.针对属性不存在,通过如下对数据新增属性
this.$set(this.dateSelect,"receiveType",this.typeValue);
//子组件watch(子组件接收父组件传递过来的参数,名为params)
watch{
params(newValue,oldValue){
//子组件能够监听到params对象的变化
},
receiveType(newValue,oldValue){
//子组件无法监听到属性receiveType的变化
}
}
总结:watch监听---只能监听①单独属性的变化 ②对象数据的变化(无法监听对象中具体属性的变化)
②针对①中【属性存在,默认为空情况,通过=的形式修改,无法监听到params的变化】,那么怎么才能够监听到呢?
//1.使用handler函数 2.添加deep属性
watch{
params:{
handler(newVal,oldVal){
},
deep:true
}
}
提示:只要params中的属性发生变化(可被监听到的),便会执行handler函数;如果想监测具体的属性变化,如receiveType变化时,才执行handler函数,则可以利用计算属性computed做中间层。
③子组件中,使用computed属性,来监听对象具体属性的变化
//通过watch监听receiveType属性的变化,然后通过计算属性computed来获取具体变化的值
computed:{
receiveType(){
return this.params.receiveType;
}
},
watch:{
//监听父组件传递的dateType,
receiveType(newValue,oldValue){
console.log(newValue);//此处即为变化后的receiveType属性值
}
}
至此:子组件便可以监听到父组件实时传递过来的receiveType属性,然后同步做出一些相关操作,达到数据驱动的效果。