Home  >  Article  >  Web Front-end  >  Introduction to 8 ways to communicate with Vue components (Collection)

Introduction to 8 ways to communicate with Vue components (Collection)

青灯夜游
青灯夜游forward
2020-07-09 15:20:044004browse

Introduction to 8 ways to communicate with Vue components (Collection)

vue is a framework for data-driven view updates, so data communication between components is very important for vue. So how do data communication occur between components? First of all, we need to know what kind of relationship exists between components in Vue, so that it is easier to understand their communication methods.

Relationship description in the vue component:

Introduction to 8 ways to communicate with Vue components (Collection)

As shown in the picture above, A and B, A and C, B and D, The relationship between components C and E is a father-son relationship; the relationship between B and C is a brother; the relationship between A and D, and A and E is a generational relationship; the relationship between D and E is a cousin (not an immediate relative). For the above relationships, we The class is:

  1. Communication between parent and child components

  2. Communication between non-parent and child components (sibling components, generation-separated components, etc.)

1. props / $emit

The parent component passes data to the child component through props, and through $emit Child components can communicate with parent components.

1. Parent component passes value to child component

How the parent component passes data to the child component: How to get the parent component section.vue in the child component article.vue Data in articles

// section父组件
<template>
 <p class="section">
 <com-article :articles="articleList"></com-article>
 </p>
</template>
<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { comArticle },
 data() {
 return {
 articleList: [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;,&#39;four&#39;,&#39;fives&#39;]
 }
 }
}
</script>
// 子组件 article.vue
<template>
 <p>
 <span v-for="(item, index) in articles" :key="index">{{item}}</span>
 </p>
</template>
<script>
export default {
 props: [&#39;articles&#39;]
}
</script>

Summary: prop can only be passed from the upper-level component to the lower-level component (parent-child component), which is the so-called one-way data flow. Moreover, prop is read-only and cannot be modified. All modifications will be invalid and a warning will be issued.

2. The child component passes the value to the parent component

My own understanding of $emit is this: $emit binds a custom event, When this statement is executed, the parameter arg will be passed to the parent component, and the parent component listens and receives the parameters through v-on. Through an example, explain how the child component passes data to the parent component. Based on the previous example, click on the ariticle item rendered by the page, and the subscript

// 父组件中
<template>
 <p class="section">
 <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
 <p>{{currentIndex}}</p>
 </p>
</template>
<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { comArticle },
 data() {
 return {
 currentIndex: -1,
 articleList: [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;,&#39;four&#39;,&#39;fives&#39;]
 }
 },
 methods: {
 onEmitIndex(idx) {
 this.currentIndex = idx
 }
 }
}
</script>
<template>
 <p>
 <p v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</p>
 </p>
</template>
<script>
export default {
 props: [&#39;articles&#39;],
 methods: {
 emitIndex(index) {
 this.$emit(&#39;onEmitIndex&#39;, index)
 }
 }
}
</script>
// 父组件中
<template>
 <p class="hello_world">
 <p>{{msg}}</p>
 <com-a></com-a>
 <button @click="changeA">点击改变子组件值</button>
 </p>
</template>
<script>
import ComA from &#39;./test/comA.vue&#39;
export default {
 name: &#39;HelloWorld&#39;,
 components: { ComA },
 data() {
 return {
 msg: &#39;Welcome&#39;
 }
 },
 methods: {
 changeA() {
 // 获取到子组件A
 this.$children[0].messageA = &#39;this is new value&#39;
 }
 }
}
</script>
// 子组件中
<template>
 <p class="com_a">
 <span>{{messageA}}</span>
 <p>获取父组件的值为: {{parentVal}}</p>
 </p>
</template>
<script>
export default {
 data() {
 return {
 messageA: &#39;this is old&#39;
 }
 },
 computed:{
 parentVal(){
 return this.$parent.msg;
 }
 }
}
</script>

in the parent component is displayed in the array. Pay attention to boundary conditions, such as taking $parent on #app What you get is an instance of new Vue(). If you take $parent on this instance, you get undefined, and if you take $children on the bottom child component, it is an empty array. Also note that the values ​​​​of $parent and $children are different. The value of $children is an array, and $parent is an object.
Summary
The above two methods are used for communication between parent and child components, and props are used for communication. Parent-child component communication is more common; neither can be used for communication between non-parent-child components.

3. provide/ inject

Concept:

provide/ inject is a new API of vue2.2.0, simple In other words, the parent component provides variables through provide, and then injects variables into the child component through inject.
Note: No matter how deeply the sub-component is nested here, as long as inject is called, the data in provide can be injected, and it is not limited to returning data from the props attribute of the current parent component

Example verification

Next, use an example to verify the above description: Suppose there are three components: A.vue, B.vue, C.vue, where C is a subcomponent of B, and B is a subcomponent of A.

// A.vue
<template>
 <p>
	<comB></comB>
 </p>
</template>
<script>
 import comB from &#39;../components/test/comB.vue&#39;
 export default {
 name: "A",
 provide: {
 for: "demo"
 },
 components:{
 comB
 }
 }
</script>
// B.vue
<template>
 <p>
 {{demo}}
 <comC></comC>
 </p>
</template>
<script>
 import comC from &#39;../components/test/comC.vue&#39;
 export default {
 name: "B",
 inject: [&#39;for&#39;],
 data() {
 return {
 demo: this.for
 }
 },
 components: {
 comC
 }
 }
</script>
// C.vue
<template>
 <p>
 {{demo}}
 </p>
</template>
<script>
 export default {
 name: "C",
 inject: [&#39;for&#39;],
 data() {
 return {
 demo: this.for
 }
 }
 }
</script>

4. ref / refs

ref: If used on a normal DOM element, the reference points to the DOM element; if used On a subcomponent, the reference points to the component instance. You can directly call the component's method or access data through the instance. Let's look at an example of accessing the component using ref:

// 子组件 A.vue
export default {
 data () {
 return {
 name: &#39;Vue.js&#39;
 }
 },
 methods: {
 sayHello () {
 console.log(&#39;hello&#39;)
 }
 }
}
// 父组件 app.vue
<template>
 <component-a ref="comA"></component-a>
</template>
<script>
 export default {
 mounted () {
 const comA = this.$refs.comA;
 console.log(comA.name); // Vue.js
 comA.sayHello(); // hello
 }
 }
</script>

5 , eventBus

eventBus is also called event bus. It can be used as a communication bridge concept in vue. It is like all components share the same event center and can register with the center. Send events or receive events, so components can notify other components.

EventBus also has inconveniences. When the project is large, it can easily cause disasters that are difficult to maintain.

How to use eventBus to achieve data communication between components in Vue projects? Specifically Through the following steps

1. Initialization

First you need to create an event bus and export it so that other modules can use or monitor it.

// event-bus.js
import Vue from &#39;vue&#39;
export const EventBus = new Vue()

2. Send events

Suppose you have two components: additionNum and showNum. These two components can be sibling components or parent-child components; here we use sibling components as Example:

<template>
 <p>
 <show-num-com></show-num-com>
 <addition-num-com></addition-num-com>
 </p>
</template>
<script>
import showNumCom from &#39;./showNum.vue&#39;
import additionNumCom from &#39;./additionNum.vue&#39;
export default {
 components: { showNumCom, additionNumCom }
}
</script>
// addtionNum.vue 中发送事件
<template>
 <p>
 <button @click="additionHandle">+加法器</button> 
 </p>
</template>
<script>
import {EventBus} from &#39;./event-bus.js&#39;
console.log(EventBus)
export default {
 data(){
 return{
 num:1
 }
 },
 methods:{
 additionHandle(){
 EventBus.$emit(&#39;addition&#39;, {
 num:this.num++
 })
 }
 }
}
</script>

3. Receive the event

// showNum.vue 中接收事件
<template>
 <p>计算和: {{count}}</p>
</template>
<script>
import { EventBus } from &#39;./event-bus.js&#39;
export default {
 data() {
 return {
 count: 0
 }
 },
 mounted() {
 EventBus.$on(&#39;addition&#39;, param => {
 this.count = this.count + param.num;
 })
 }
}
</script>

This way, click the add button in the component additionNum.vue, in showNum. In vue, the passed num is used to display the summation result.

4. Remove the event listener

If you want to remove the event listener, you can do as follows Operation:

import { eventBus } from &#39;event-bus.js&#39;
EventBus.$off(&#39;addition&#39;, {})

6. Vuex

##1. Introduction to Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex 解决了多个视图依赖于同一状态和来自不同视图的行为需要变更同一状态的问题,将开发者的精力聚焦于数据的更新而不是数据在组件之间的传递上

2、Vuex各个模块

state:用于数据的存储,是store中的唯一数据源
getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
mutations:类似函数,改变state数据的唯一途径,且不能用于处理异步事件
actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

3、Vuex实例应用

// 父组件
<template>
 <p id="app">
 <ChildA/>
 <ChildB/>
 </p>
</template>
<script>
 import ChildA from &#39;./components/ChildA&#39; // 导入A组件
 import ChildB from &#39;./components/ChildB&#39; // 导入B组件
 export default {
 name: &#39;App&#39;,
 components: {ChildA, ChildB} // 注册A、B组件
 }
</script>
// 子组件childA
<template>
 <p id="childA">
 <h1>我是A组件</h1>
 <button @click="transform">点我让B组件接收到数据</button>
 <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
 </p>
</template>
<script>
 export default {
 data() {
 return {
 AMessage: &#39;Hello,B组件,我是A组件&#39;
 }
 },
 computed: {
 BMessage() {
 // 这里存储从store里获取的B组件的数据
 return this.$store.state.BMsg
 }
 },
 methods: {
 transform() {
 // 触发receiveAMsg,将A组件的数据存放到store里去
 this.$store.commit(&#39;receiveAMsg&#39;, {
 AMsg: this.AMessage
 })
 }
 }
 }
</script>
// 子组件 childB
<template>
 <p id="childB">
 <h1>我是B组件</h1>
 <button @click="transform">点我让A组件接收到数据</button>
 <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
 </p>
</template>
<script>
 export default {
 data() {
 return {
 BMessage: &#39;Hello,A组件,我是B组件&#39;
 }
 },
 computed: {
 AMessage() {
 // 这里存储从store里获取的A组件的数据
 return this.$store.state.AMsg
 }
 },
 methods: {
 transform() {
 // 触发receiveBMsg,将B组件的数据存放到store里去
 this.$store.commit(&#39;receiveBMsg&#39;, {
 BMsg: this.BMessage
 })
 }
 }
 }
</script>
vuex的store,js
import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
Vue.use(Vuex)
const state = {
 // 初始化A和B组件的数据,等待获取
 AMsg: &#39;&#39;,
 BMsg: &#39;&#39;
}
const mutations = {
 receiveAMsg(state, payload) {
 // 将A组件的数据存放于state
 state.AMsg = payload.AMsg
 },
 receiveBMsg(state, payload) {
 // 将B组件的数据存放于state
 state.BMsg = payload.BMsg
 }
}
export default new Vuex.Store({
 state,
 mutations
})

 七、localStorage / sessionStorage

这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。 通过window.localStorage.getItem(key)获取数据 通过window.localStorage.setItem(key,value)存储数据

注意用JSON.parse() / JSON.stringify() 做数据格式转换 localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.

 八 $attrs与 $listeners

现在我们来讨论一种情况, 我们一开始给出的组件关系图中A组件与D组件是隔代关系, 那它们之前进行通信有哪些方式呢?

  1. 使用props绑定来进行一级一级的信息传递, 如果D组件中状态改变需要传递数据给A, 使用事件系统一级级往上传递

  2. 使用eventBus,这种情况下还是比较适合使用, 但是碰到多人合作开发时, 代码维护性较低, 可读性也低

  3. 使用Vuex来进行数据管理, 但是如果仅仅是传递数据, 而不做中间处理,使用Vuex处理感觉有点大材小用了.

在vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上。接下来看一个跨级通信的例子:

// app.vue
// index.vue
<template>
 <p>
 <child-com1
 :name="name"
 :age="age"
 :gender="gender"
 :height="height"
 title="程序员成长"
 ></child-com1>
 </p>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
 components: { childCom1 },
 data() {
 return {
 name: "zhang",
 age: "18",
 gender: "女",
 height: "158"
 };
 }
};
</script>
// childCom1.vue
<template class="border">
 <p>
 <p>name: {{ name}}</p>
 <p>childCom1的$attrs: {{ $attrs }}</p>
 <child-com2 v-bind="$attrs"></child-com2>
 </p>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
 components: {
 childCom2
 },
 inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
 props: {
 name: String // name作为props属性绑定
 },
 created() {
 console.log(this.$attrs);
 // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长" }
 }
};
</script>
// childCom2.vue
<template>
 <p class="border">
 <p>age: {{ age}}</p>
 <p>childCom2: {{ $attrs }}</p>
 </p>
</template>
<script>
export default {
 inheritAttrs: false,
 props: {
 age: String
 },
 created() {
 console.log(this.$attrs); 
 // { "gender": "女", "height": "158", "title": "程序员成长指北" }
 }
};
</script>

总结

常见使用场景可以分为三类:
父子组件通信: props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
兄弟组件通信: eventBus ; vuex
跨级通信: eventBus;Vuex;provide / inject 、$attrs / $listeners

The above is the detailed content of Introduction to 8 ways to communicate with Vue components (Collection). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete