Table of Contents
我是A组件
我是B组件
Home Web Front-end JS Tutorial Introduction to 8 ways to communicate with Vue components (Collection)

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

Jul 09, 2020 pm 03:20 PM
vue Component communication

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>
Copy after login

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>
Copy after login
// 父组件中
<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>
Copy after login

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>
Copy after login

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>
Copy after login

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()
Copy after login

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>
Copy after login

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>
Copy after login

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;, {})
Copy after login

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 id="我是A组件">我是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 id="我是B组件">我是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
})
Copy after login

七、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>
Copy after login

总结

常见使用场景可以分为三类:
父子组件通信: 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 of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to use bootstrap in vue How to use bootstrap in vue Apr 07, 2025 pm 11:33 PM

Using Bootstrap in Vue.js is divided into five steps: Install Bootstrap. Import Bootstrap in main.js. Use the Bootstrap component directly in the template. Optional: Custom style. Optional: Use plug-ins.

How to add functions to buttons for vue How to add functions to buttons for vue Apr 08, 2025 am 08:51 AM

You can add a function to the Vue button by binding the button in the HTML template to a method. Define the method and write function logic in the Vue instance.

How to reference js file with vue.js How to reference js file with vue.js Apr 07, 2025 pm 11:27 PM

There are three ways to refer to JS files in Vue.js: directly specify the path using the &lt;script&gt; tag;; dynamic import using the mounted() lifecycle hook; and importing through the Vuex state management library.

How to use watch in vue How to use watch in vue Apr 07, 2025 pm 11:36 PM

The watch option in Vue.js allows developers to listen for changes in specific data. When the data changes, watch triggers a callback function to perform update views or other tasks. Its configuration options include immediate, which specifies whether to execute a callback immediately, and deep, which specifies whether to recursively listen to changes to objects or arrays.

What does vue multi-page development mean? What does vue multi-page development mean? Apr 07, 2025 pm 11:57 PM

Vue multi-page development is a way to build applications using the Vue.js framework, where the application is divided into separate pages: Code Maintenance: Splitting the application into multiple pages can make the code easier to manage and maintain. Modularity: Each page can be used as a separate module for easy reuse and replacement. Simple routing: Navigation between pages can be managed through simple routing configuration. SEO Optimization: Each page has its own URL, which helps SEO.

How to return to previous page by vue How to return to previous page by vue Apr 07, 2025 pm 11:30 PM

Vue.js has four methods to return to the previous page: $router.go(-1)$router.back() uses &lt;router-link to=&quot;/&quot; component window.history.back(), and the method selection depends on the scene.

How to query the version of vue How to query the version of vue Apr 07, 2025 pm 11:24 PM

You can query the Vue version by using Vue Devtools to view the Vue tab in the browser's console. Use npm to run the "npm list -g vue" command. Find the Vue item in the "dependencies" object of the package.json file. For Vue CLI projects, run the "vue --version" command. Check the version information in the &lt;script&gt; tag in the HTML file that refers to the Vue file.

How to use function intercept vue How to use function intercept vue Apr 08, 2025 am 06:51 AM

Function interception in Vue is a technique used to limit the number of times a function is called within a specified time period and prevent performance problems. The implementation method is: import the lodash library: import { debounce } from 'lodash'; Use the debounce function to create an intercept function: const debouncedFunction = debounce(() =&gt; { / Logical / }, 500); Call the intercept function, and the control function is called at most once in 500 milliseconds.

See all articles