Preface: In actual work, there are many scenarios where data is processed in child components and data changes need to be obtained synchronously in parent components. For example, a query page has many query conditions. Suppose there is a sub-component that selects components for regions. We need to perform the query operation immediately after selecting the region. At this time, we need to synchronize the data between the parent and child components.
1. Definition and introduction of subcomponents
There are two ways to define subcomponents: global registration and local registration. However, in my actual work, I basically use local registration to define the subcomponent as a file. The parent component introduces the subcomponent and registers .vue
the import
subcomponent components
in :
parent component
import AreasSelector from '@/components/AreasSelector/index';
...
components: {
AreasSelector
},
When using a subcomponent in a parent component, you must design what parameters the subcomponent can accept and what parameters it should return, based on the respective business scenarios.
Here my child component can receive two parameters passed from the parent component: one is the areaIds
region that has been selected in the parent component ids
; the other is isMulti
whether the region supports multiple selections. You need to use it when passing data from a parent component to a child component props
. If you are passing static data (strings, numbers, etc.), you don't need to add it :
. If you want to pass dynamic data (data that needs to be obtained from the current component instance), you need to add it :
.
The parameters to be returned by the subcomponent are those selected after the user clicks the behavior areaIds
. $on
To receive the parameters returned by the subcomponent, you need to define a callback function where the subcomponent is used, which is equivalent to an observer:
in the parent component
<AreasSelector :props="{areaIds,isMulti:true}" @area-change="onAreaChange"></AreasSelector>
Where data needs to be sent in a subcomponent, use $emit
Send Data, which is equivalent to a publisher:
in the subcomponent
this.$emit('area-change', newVal);
$on
And $emit
the observer mode is used, that is, $emit
you need to find all the $on
defined callback functions, and then execute all the callback functions. You can simply take a look at vue
the source code. I only kept the most critical parts:
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
};
Second, watch
Inside the child component, when the user clicks on a region, a series of processing is required, and the processing is converted into a region id
array and passed to the parent component. We can manually call the process of passing it to the parent component $emit
, or we can leave it watch
to monitor data changes and watch
call it internally $emit
.
The watch official document
watch
is vue
an attribute object that can be set by the component. data
It is used to monitor vue
changes in data in the component. There are three definition forms key
for the data that needs to be monitored : ① The method name of the callback function, a string ② Object, in which The attribute is a callback function method. When the attribute is , it means that the callback function will also be triggered when the deep attributes of the monitored target object change; when the attribute is set to , it will be called immediately after the listening starts ③ Callback function array, they will be executed in sequence We can define one for the data that needs to be passed to the parent component , monitor its changes in real time, and automatically call :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
}
},