Vue实际应用之父子组件双向数据绑定

前言:在实际工作中,有很多这样的场景:在子组件中进行数据的处理,在父组件中需要同步获取数据变化。比如一个查询页面,有很多的查询条件,假设现在有一个子组件为地区选择组件,我们需要选择完地区之后,立即进行查询操作,这时候就需要将这个数据在父子组件之间同步变化。

一、子组件的定义和引入

子组件定义的方式有全局注册和局部注册两种,不过在我实际工作中,基本上都是用局部注册,把子组件定义成一个.vue文件,父组件通过import引入子组件,并且在components中注册子组件:
父组件

import AreasSelector from '@/components/AreasSelector/index';
... 
components: {
    
    
    AreasSelector
},

在父组件中使用子组件,要设计好子组件可以接受什么参数、以及要返回什么参数,根据各自的业务场景决定。
这里我的子组件的可以接收父组件传过来的两个参数:一个是areaIds,即父组件中已经选择的地区ids;一个是isMulti,即地区是否支持多选。父组件向子组件传递数据需要使用props,如果传递的是静态数据(字符串、数字等)不需要加:,传递动态数据(需要从当前组件实例上获取的数据)需要加:
子组件要返回的参数就是用户点击行为之后选中的areaIds。接收子组件返回的参数,需要在使用子组件的地方,使用$on定义一个回调函数,相当于一个观察者:
父组件中

<AreasSelector :props="{areaIds,isMulti:true}" @area-change="onAreaChange"></AreasSelector>

在子组件中需要发送数据的地方,使用$emit发送数据,相当于一个发布者:
子组件中

this.$emit('area-change', newVal);

$on$emit使用的是观察者模式,即在$emit中需要找到所有的$on定义的回调函数,然后执行所有的回调函数,可以简单看一下vue的源码,我只保留了最关键的部分:

Vue.prototype.$emit = function (event) {
    
    
  var vm = this;
  // cbs中存储着$on定义的回调函数列表
  var cbs = vm._events[event];
  if (cbs) {
    
    
    cbs = cbs.length > 1 ? toArray(cbs) : cbs;
    var args = toArray(arguments, 1);
    var info = "event handler for \"" + event + "\"";
    for (var i = 0, l = cbs.length; i < l; i++) {
    
    
    	// 到这个函数中执行回调函数
      invokeWithErrorHandling(cbs[i], vm, args, vm, info);
    }
  }
  return vm
};

二、watch

在子组件的内部,用户点击地区时需要进行一系列的处理,处理成地区id数组传递给父组件。传递给父组件这一过程,我们可以手动调用$emit,也可以交给watch去监听数据变化,在watch内部调用$emit
watch官方文档
watchvue组件可以设置的一个属性对象,和data平级,用来监听vue组件中数据的变化,key为需要监听的数据,value有三种定义形式:
① 回调函数的方法名,字符串
② 对象,其中的handler属性是一个回调函数方法,deep属性为true时,表示监听的目标对象的深层属性变化时也会触发回调函数;immediate属性设置为true时,会在侦听开始之后被立即调用
③ 回调函数数组,它们会依次执行
我们可以为需要传递给父组件的数据定义一个watcher,实时监听其变化,并且自动调用$emit

watch: {
    
    
    'areaData': {
    
    
        handler(newVal, oldVal) {
    
    
            if (!newVal) return;
            this.$emit('area-change', newVal);
        },
        deep: true,
        immediate: true
    }
},

猜你喜欢

转载自blog.csdn.net/weixin_45855469/article/details/131759278