Communication between vue components

There are currently four known communication methods: vuex, $emit $v-on props, Event Bus, $attrs $listeners

1. Let's talk about $attr, $listeners first

$attrs

 Contains property bindings (except class and style) that are not considered (and are not expected to be) props in the parent scope. When a component does not declare any props, all parent-scoped bindings (except class and style) are included here, and can be passed to inner components via v-bind=”$attrs” - when creating higher-level components very useful.

$listeners

Contains the v-on event listener in the parent scope (without the .native decorator). It can be passed into internal components via v-on=”$listeners” - very useful when creating higher level components.

inheritAttrs

Parent-scoped attribute bindings that are not considered props by default will "fall back" and be applied to the root element of the child component as normal HTML attributes. This may not always behave as expected when writing components that wrap a target element or another component. By setting inheritAttrs to false, these default behaviors will be removed. And through (also new in 2.4) instance attributes $attrs can make these features take effect, and can be bound to non-root elements explicitly through v-bind.

The use of the above features can completely reduce the complexity of component cross-level props and event delivery without using Vuex and event bus.

When multi-level component nesting needs to pass data, the usually used method is through vuex. If you just pass data without intermediate processing, using vuex processing is a bit of a knife. The Vue2.4 version provides another method, using v-bind="$attrs", to pass attributes in the parent component that are not considered props attribute binding to the child component, usually used together with the interAttrs option. The reason why these two properties are mentioned is that the appearance of the two makes the communication between components across components become concise and business clear without relying on vuex and event bus.

First analyze the following scenarios:

A component is the parent of B component, B component is the parent of C component

Communication between A component and B component (parent-child component)

Communication between parent and child components can be implemented in three ways:

1. A to B is passed to subcomponents through props, and B to A is implemented by $emit in B component and V-ON in A component.

2. By setting the global Vuex shared state, the data acquisition and update are realized by means of computed properties and commit mutation, so as to achieve the purpose of communication between parent and child components;

3. Vue Event Bus, using the instance of Vue to monitor and publish events, and realize the transfer between components

Often, the first method can be used when the data does not need to be global but only communicates between parent and child components.

Communication between A component and C component

The A component and the C component belong to a multi-level component nesting relationship. In the past, if communication between the two needed to be achieved, it was often achieved in the following ways:

1. With the help of the transfer of component B, PROPS are transmitted in sequence from top to bottom, and from bottom to top, the transmission of $emit event achieves the effect of cross-component communication

2. With the help of Vuex's global state sharing;

3. Vue Event Bus, using the instance of Vue, to monitor and publish events, and realize the transfer between components.

Obviously, the first method of props and $emit makes the business logic between components bloated, and component B only acts as a transit station. For example, using the second Vuex method seems to be overkill in some cases (just want to realize a data transfer between components, not the concept of data sharing). The use of the third situation is found in actual project operations. If the management of event monitoring and release cannot be implemented well, it is often easy to cause confusion in the data flow. In a multi-person collaborative project, it is not conducive to project maintenance.

The emergence of $attr and $listener solves the problem of the first case. In the process of passing props and events in component B, there is no need to write redundant code, just pass $attrs and $listeners up or down. Can.

A component (App.vue)

< template >
  < div id = "app" >
  < child1
  :p-child1 = "child1"
  :p-child2 = "child2"
  v-on:test1 = "onTest1" //此处监听了两个事件,可以在B组件或者C组件中直接触发
  v-on:test2 = "onTest2" >
  </ child1 >
  </ div >
</ template >
< script >
  import Child1 from './Child1.vue';
  export default {
  data () {
  return {};
  },
  components: { Child1 },
  methods: {
  onTest1 () {
  console.log('test1 running...');
  },
  onTest2 () {
  console.log('test2 running');
  }
  }
  };
</ script >

B component (Child1.vue)

< template >
  < div class = "child-1" >
  < p >in child1:</ p >
  < p >props: {{pChild1}}</ p >
  < p >$attrs: {{$attrs}}</ p >
  < hr >
  <!-- C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 -->
  <!-- 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) -->
  < child2 v-bind = "$attrs" v-on = "$listeners" ></ child2 >
  </ div >
</ template >
< script >
  import Child2 from './Child2.vue';
  export default {
  props: ['pChild1'],
  data () {
  return {};
  },
  inheritAttrs: false,
  components: { Child2 },
  mounted () {
  this.$emit('test1');
  }
  };
</ script >
result:

in child1:

props: v_child1

$attrs: { “p-child2”: “v_child2”}

C component (Child2.vue)

< template >
  < div class = "child-2" >
  < p >in child2:</ p >
  < p >props: {{pChild2}}</ p >
  < p >$attrs: {{$attrs}}</ p >
  < hr >
  </ div >
</ template >
< script >
  export default {
  props: ['pChild2'],
  data () {
  return {};
  },
  inheritAttrs: false,
  mounted () {
  this.$emit('test2');
  }
  };
</ script >

result:

in child2:

props: v_child2

$attrs: {}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326104062&siteId=291194637