搜索
首页web前端Vue.js详解8种vue组件通信方式,快来收藏!

本篇文章带大家详细了解一下vue中8种组件通信方式。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

详解8种vue组件通信方式,快来收藏!

vue是数据驱动视图更新的框架,所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?

首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式, 就好像过年回家,坐着一屋子的陌生人,相互之间怎么称呼,这时就需要先知道自己和他们之间是什么样的关系。(学习视频分享:vue视频教程

vue组件中关系说明:

1.png

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

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

本文会介绍组件间通信的8种方式如下图目录所示:并介绍在不同的场景下如何选择有效方式实现的组件间通信方式,希望可以帮助小伙伴们更好理解组件间的通信。

2.png

一、props / $emit


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

1. 父组件向子组件传值

下面通过一个例子说明父组件如何向子组件传递数据:在子组件article.vue中如何获取父组件section.vue中的数据articles:['红楼梦', '西游记','三国演义']

// section父组件
<template>
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
</template>

<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
  name: &#39;HelloWorld&#39;,
  components: { comArticle },
  data() {
    return {
      articleList: [&#39;红楼梦&#39;, &#39;西游记&#39;, &#39;三国演义&#39;]
    }
  }
}
</script>
// 子组件 article.vue
<template>
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
</template>

<script>
export default {
  props: [&#39;articles&#39;]
}
</script>
总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

2. 子组件向父组件传值

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

// 父组件中
<template>
  <div class="section">
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import comArticle from &#39;./test/article.vue&#39;
export default {
  name: &#39;HelloWorld&#39;,
  components: { comArticle },
  data() {
    return {
      currentIndex: -1,
      articleList: [&#39;红楼梦&#39;, &#39;西游记&#39;, &#39;三国演义&#39;]
    }
  },
  methods: {
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
}
</script>
<template>
  <div>
    <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>

<script>
export default {
  props: [&#39;articles&#39;],
  methods: {
    emitIndex(index) {
      this.$emit(&#39;onEmitIndex&#39;, index)
    }
  }
}
</script>

二、  $children / $parent


3.png

上面这张图片是vue官方的解释,通过$parent$children就可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data。接下来就是怎么实现拿到指定组件的实例。

使用方法

// 父组件中
<template>
  <div class="hello_world">
    <div>{{msg}}</div>
    <com-a></com-a>
    <button @click="changeA">点击改变子组件值</button>
  </div>
</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>
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>获取父组件的值为:  {{parentVal}}</p>
  </div>
</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/ injectvue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。

注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

举例验证

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

// A.vue

<template>
  <div>
    <comB></comB>
  </div>
</template>

<script>
  import comB from &#39;../components/test/comB.vue&#39;
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</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>
  <div>
    {{demo}}
  </div>
</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. 发送事件

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

<template>
  <div>
    <show-num-com></show-num-com>
    <addition-num-com></addition-num-com>
  </div>
</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>
  <div>
    <button @click="additionHandle">+加法器</button>    
  </div>
</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>
  <div>计算和: {{count}}</div>
</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>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</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>
  <div id="childA">
    <h1>我是A组件</h1>
    <button @click="transform">点我让B组件接收到数据</button>
    <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
  </div>
</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>
  <div id="childB">
    <h1>我是B组件</h1>
    <button @click="transform">点我让A组件接收到数据</button>
    <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
  </div>
</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组件是隔代关系, 那它们之前进行通信有哪些方式呢?

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

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

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

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

// app.vue
// index.vue

<template>
  <div>
    <child-com1
      :name="name"
      :age="age"
      :gender="gender"
      :height="height"
      title="程序员成长指北"
    ></child-com1>
  </div>
</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">
  <div>
    <p>name: {{ name}}</p>
    <p>childCom1的$attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</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>
  <div class="border">
    <p>age: {{ age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
</template>
<script>

export default {
  inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log(this.$attrs); 
    // { "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>

更多编程相关知识,请访问:编程视频!!

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

声明
本文转载于:segmentfault。如有侵权,请联系admin@php.cn删除
vue.js的功能:增强前端的用户体验vue.js的功能:增强前端的用户体验Apr 19, 2025 am 12:13 AM

Vue.js通过多种功能提升用户体验:1.响应式系统实现数据即时反馈;2.组件化开发提高代码复用性;3.VueRouter提供平滑导航;4.动态数据绑定和过渡动画增强交互效果;5.错误处理机制确保用户反馈;6.性能优化和最佳实践提升应用性能。

vue.js:定义其在网络开发中的作用vue.js:定义其在网络开发中的作用Apr 18, 2025 am 12:07 AM

Vue.js在Web开发中的角色是作为一个渐进式JavaScript框架,简化开发过程并提高效率。1)它通过响应式数据绑定和组件化开发,使开发者能专注于业务逻辑。2)Vue.js的工作原理依赖于响应式系统和虚拟DOM,优化性能。3)实际项目中,使用Vuex管理全局状态和优化数据响应性是常见实践。

了解vue.js:主要是前端框架了解vue.js:主要是前端框架Apr 17, 2025 am 12:20 AM

Vue.js是由尤雨溪在2014年发布的渐进式JavaScript框架,用于构建用户界面。它的核心优势包括:1.响应式数据绑定,数据变化自动更新视图;2.组件化开发,UI可拆分为独立、可复用的组件。

Netflix的前端:React(或VUE)的示例和应用Netflix的前端:React(或VUE)的示例和应用Apr 16, 2025 am 12:08 AM

Netflix使用React作为其前端框架。1)React的组件化开发模式和强大生态系统是Netflix选择它的主要原因。2)通过组件化,Netflix将复杂界面拆分成可管理的小块,如视频播放器、推荐列表和用户评论。3)React的虚拟DOM和组件生命周期优化了渲染效率和用户交互管理。

前端景观:Netflix如何处理其选择前端景观:Netflix如何处理其选择Apr 15, 2025 am 12:13 AM

Netflix在前端技术上的选择主要集中在性能优化、可扩展性和用户体验三个方面。1.性能优化:Netflix选择React作为主要框架,并开发了SpeedCurve和Boomerang等工具来监控和优化用户体验。2.可扩展性:他们采用微前端架构,将应用拆分为独立模块,提高开发效率和系统扩展性。3.用户体验:Netflix使用Material-UI组件库,通过A/B测试和用户反馈不断优化界面,确保一致性和美观性。

React与Vue:Netflix使用哪个框架?React与Vue:Netflix使用哪个框架?Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVueDirectly.1)TeamExperience:selectBasedAsedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects,vueforsimplerprojects,reactforforforecomplexones.3)cocatizationNeedsneeds:reactofficatizationneedneeds:reactofferizationneedneedneedneeds:reactoffersizatization needeffersefersmoreflexiblesimore.4)ecosyaka

框架的选择:是什么推动了Netflix的决定?框架的选择:是什么推动了Netflix的决定?Apr 13, 2025 am 12:05 AM

Netflix在框架选择上主要考虑性能、可扩展性、开发效率、生态系统、技术债务和维护成本。1.性能与可扩展性:选择Java和SpringBoot以高效处理海量数据和高并发请求。2.开发效率与生态系统:使用React提升前端开发效率,利用其丰富的生态系统。3.技术债务与维护成本:选择Node.js构建微服务,降低维护成本和技术债务。

反应,vue和Netflix前端的未来反应,vue和Netflix前端的未来Apr 12, 2025 am 12:12 AM

Netflix主要使用React作为前端框架,辅以Vue用于特定功能。1)React的组件化和虚拟DOM提升了Netflix应用的性能和开发效率。2)Vue在Netflix的内部工具和小型项目中应用,其灵活性和易用性是关键。

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无尽的。

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器