Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

8 modes of communication between Vue components


Jun 01, 2021 Article blog


Table of contents


preface

Vue offers a wide variety of communications, including 兄弟间 and 非兄弟间 which is easy to summarize and access.

1、props

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1

The structure of the code

Use the son component in the father component to give the son a one-way pass value through :date="xxx"

<template>
  <div>
    <div>爸爸:{{date}}</div>
    <Son1 :date="date"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      date: 1,
    };
  },
};
</script>

The son component accepts the value passed by the parent component through props

<template>
  <div>儿子:{{date}}</div>
</template>
<script>
export default {
  props: {
    date: {
      type: Number, //校验类型
      default: "1",
    },
  },
};
</script>

2、$emit

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1

The structure of the code

(Recommended tutorial: Vue 2 tutorial)

The child component triggers $emit method by touching itself, and then the parent component's method, passing the modified content to the parent component by calling back the 回调传参

<template>
  <div>
    <div>儿子:{{date}}</div>
    <button @click="changeNum">修改</button>
  </div>
</template>
<script>
export default {
  props: {
    date: {
      type: Number,
      default: "1",
    },
  },
  methods: {
    changeNum() {
      this.$emit("changeNum", 2);
    },
  },
};
</script>

The parent component accepts the callback params parameter, which means that the father needs to bind a custom event to his $on("changeNum",params)

<template>
  <div>
    <div>爸爸:{{date}}</div>
    <Son1 :date="date" @changeNum="changeNum"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      date: 1,
    };
  },
  methods: {
    changeNum(params) {
      this.date = params;
    },
  },
};
</script>

.sync

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1

The structure of the code

Subcommys transmit events through $emit("update:xxx")

<template>
  <div>
    <div>儿子:{{date}}</div>
    <button @click="changeNum">修改</button>
  </div>
</template>
<script>
export default {
  props: {
    date: {
      type: Number,
      default: "1",
    },
  },
  methods: {
    changeNum() {
      this.$emit("update:date", 2);
    },
  },
};
</script>

The parent component accepts the argument by :xxx.sync="xxx"

<template>
  <div>
    <div>爸爸:{{date}}</div>
    <Son1 :date.sync="date"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      date: 1,
    };
  },
};
</script>
<Son1 :date.sync="date"></Son1>
//这个写法是上面的替代品 默认组件内部触发 update:count 规定写法
<Son1 :date="date" @update:date="val=>date=val"></Son1>

v-model

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1

The structure of the code

The event triggered by the child component can only be an input event, and the property name of the receiving props can only be called value

<template>
  <div>
    <div>儿子:{{value}}</div>
    <button @click="changeNum">修改</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number,
      default: 1,
    },
  },
  methods: {
    changeNum() {
      this.$emit("input", 2);
    },
  },
};
</script>

The parent component receives parameters through v-model

<template>
  <div>
    <div>爸爸:{{value}}</div>
    <Son1 v-model="value"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      value: 1,
    };
  },
};
</script>
<Son1 :value="value" @input="val=>value=val"></Son1>
//这个写法是上面的替代品 默认组件内部触发 input 规定写法
<Son1 v-model="value"></Son1>

 v-model` 局限只能传递一个属性 如果只有一个 可以使用`v-model` 多个依然需要使用`.sync

3, $parent and $children

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   ├── Grandson1.vue  //孙子1

The structure of the code

Here's the scenario: Grandson wants to pass data to grandpa, grandson needs to find grandpa's events to pass $parent.$emit

<template>
  <div>
    <div>孙子{{value}}</div>
    <button @click="$parent.$emit('change',3)">修改</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number,
      default: "",
    },
  },
};
</script>

The son component uses the grandchild component

<template>
  <div>
    <div>儿子:{{value}}</div>
    <grandson1 :value="value"></grandson1>
  </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
  components: {
    grandson1,
  },
  props: {
    value: {
      type: Number,
      default: 1,
    },
  },
};
</script>

Dad customizes change event for his grandson

<template>
  <div>
    <div>爸爸:{{value}}</div>
    <Son1 @change="val=>value=val" :value="value"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      value: 1,
    };
  },
};
</script>

If the hierarchy is deep then there will be $parent.$parent..... We can encapsulate a $dispatch method to distribute up

Vue.prototype.$dispatch = function $dispatch(eventName, data) {
  let parent = this.$parent;
  while (parent) {
    parent.$emit(eventName, data);
    parent = parent.$parent;
  }
};

By the same token, if you can find a father up, you can look down for a son, and you can encapsulate a downward distribution method $broadcast

Vue.prototype.$broadcast = function $broadcast(eventName, data) {
  const broadcast = function () {
    this.$children.forEach((child) => {
      child.$emit(eventName, data);
      if (child.$children) {
        $broadcast.call(child, eventName, data);
      }
    });
  };
  broadcast.call(this, eventName, data);
};

4, $attrs and $listeners

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   ├── Grandson1.vue  //孙子1

$attrs bulk pass-down properties

<template>
  <div>
    <div>爸爸:{{value}}</div>
    <Son1 @change="val=>value=val" :value="value"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      value: 1,
    };
  },
};
</script>

Use the $attrs property in the son component, and with v-bind you can continue the property down

<template>
  <div>
    <div>儿子:{{$attrs.value}}</div>
    <grandson1 v-bind="$attrs"></grandson1>
  </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
  components: {
    grandson1,
  },
  mounted() {
    console.log(this.$attrs);
  },
};
</script>

Note that when you use $attrs, if you use props in a component, the property is removed from the current attrs

Using $attrs property in the grandson component, you can continue the property down

<template>
  <div>
    <div>孙子{{$attrs.value}}</div>
  </div>
</template>
<script>
export default {
  //props: {
  //  value: Number,
  //},
  mounted() {
    console.log(this.$attrs);
  },
};
</script>

If the father passes the element to the son, the son has three properties that are not available, the grandson passes to the grandson, but does not want this property on the page, you can set inheritAttrs: false

$listeners batch-down method

<template>
  <div>
    <div>爸爸:{{value}}</div>
    <Son1 @click="change" :value="value"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  data() {
    return {
      value: 1,
    };
  },


  methods: {
    change() {
      this.value = 2;
    },
  },
};
</script>

You can use the $listeners property in $listeners component, and v-on you can continue the method down son1

<template>
  <div>
    <div>儿子:{{$attrs.value}}</div>
    <grandson1 v-bind="$attrs" v-on="$listeners"></grandson1>
  </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
  components: {
    grandson1,
  },
  mounted() {
    console.log(this.$attrs);
    console.log(this.$listeners);
  },
};
</script>

Sun tzu components can use the methods on $listeners directly

<template>
  <div>
    <div>孙子{{$attrs.value}}</div>
    <button @click="$listeners.click"></button>
  </div>
</template>
<script>
export default {
  mounted() {
    console.log(this.$attrs);
    console.log(this.$listeners);
  },
};
</script>

5、Provide & Inject

The directory structure

app.vue
components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1
   ├── Grandson1.vue  //孙子1

The structure of the code

Declare a public data at the parent level

export default {
  provide() {
    return { vm: this };
  },
};

Principles can be injected into subcommys that mount data on the current instance

<template>
  <div>
    <div>孙子</div>
  </div>
</template>
<script>
export default {
  inject: ["vm"],
  mounted() {
    console.log(this);
  },
};
</script>

 8 modes of communication between Vue components1

Note: This method is confusing after use, it is generally 不会在业务代码中使用 often in component libraries or multi-level communication, for your convenience you can use provide

6、ref

The directory structure

components
   ├── Parent.vue   // 父亲
   ├── Son1.vue     // 儿子1

The structure of the code

ref gets the real dom element if it represents an instance of the current component on 当前组件的实例 Methods or data for child components can be obtained directly in the parent component.

<template>
  <div>
    <div>爸爸</div>
    <Son1 ref="son"></Son1>
  </div>
</template>
<script>
import Son1 from "./son1";
export default {
  components: { Son1 },
  mounted() {
    this.$refs.son.show();
  },
};
</script>
<template>
  <div>
    <div>儿子</div>
  </div>
</template>
<script>
export default {
  methods: {
    show() {
      console.log(1);
    },
  },
};
</script>

Note: ref does not 重名 but it can cause 数组 when and only when v-for is used

7、EventBus

The directory structure

main.js
components
   ├── Grandson1.vue   // 孙子1
   ├── Son2.vue     // 儿子2

The structure of the code

EventBus can be used for cross-component notifications (not complex projects can be used this way)

Vue.prototype.$bus = new Vue();

Grandson1 component and Son2 communicate with each other

<template>
  <div>孙子1</div>
</template>
<script>
export default {
  mounted() {
    this.$nextTick(() => {
      this.$bus.$emit("test", "go");
    });
  },
};
</script>

The Son 2 component here can only use $on to trigger Grandson1 component event

<template>
  <div>儿子2</div>
</template>
<script>
export default {
  mounted() {
    this.$bus.$on("test", (data) => {
      console.log(data);
    });
  },
};
</script>

8、Vuex

Vuex is a state management model developed specifically for Vue .js applications.

 8 modes of communication between Vue components2

(Recommended micro-class: Vue 2.x micro-class)

Source: Public Number - Clown's Cabin

Author: Clown

The above is the W3Cschool programming lion about the Vue components between the eight modes of communication related to the introduction, I hope to help you.