搜索
首页web前端js教程vue组件通信的中8种方式介绍(收藏)

vue组件通信的中8种方式介绍(收藏)

vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式。 

vue组件中关系说明:

1.png

如上图所示, A与B、A与C、B与D、C与E组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与E是堂兄关系(非直系亲属) 针对以上关系我们归类为:

  1. 父子组件之间通信

  2. 非父子组件之间通信(兄弟组件、隔代关系组件等)

一、props / $emit

父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信。

1、父组件向子组件传值

父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据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>

总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

 2. 子组件向父组件传值

对于$emit 我自己的理解是这样的: $emit绑定一个自定义事件, 当这个语句被执行时, 就会将参数arg传递给父组件,父组件通过v-on监听并接收参数。 通过一个例子,说明子组件如何向父组件传递数据。 在上个例子的基础上, 点击页面渲染出来的ariticle的item, 父组件中显示在数组中的下标

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

 要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent和$children的值不一样,$children 的值是数组,而$parent是个对象
总结
上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。

三、provide/ inject

概念:

provide/ inject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

举例验证

接下来就用一个例子来验证上面的描述: 假设有三个组件: A.vue、B.vue、C.vue 其中 C是B的子组件,B是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>

 四、ref / refs

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 我们看一个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>

 五、eventBus

eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。

eventBus也有不方便之处, 当项目较大,就容易造成难以维护的灾难

在Vue的项目中怎么使用eventBus来实现组件之间的数据通信呢?具体通过下面几个步骤

1、初始化

首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.

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

2、发送事件

假设你有两个组件: additionNum 和 showNum, 这两个组件可以是兄弟组件也可以是父子组件;这里我们以兄弟组件为例:

<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. 接收事件

// 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>

这样就实现了在组件addtionNum.vue中点击相加按钮, 在showNum.vue中利用传递来的 num 展示求和的结果.

4. 移除事件监听者

如果想移除事件的监听, 可以像下面这样操作:

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

 六、Vuex

1、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

以上是vue组件通信的中8种方式介绍(收藏)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:csdn。如有侵权,请联系admin@php.cn删除
超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版