💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] Communication among components # 父向子组件通信 ## 通过属性传值 props ``` // 父组件 List.vue ... <List-item :obj="obj" :arr="arr" :func="func"></List-item> ... // 子组件 ListItem.vue <template> <div> <div>{{msg}}</div> <div>{{obj}}</div> <div>{{arr}}</div> </div> </template> <script> export default { props: { obj: Object, // props 是对象 arr: Array, // props 是数组 func: Function // props 是 方法 }, created() { this.func() } } </script> ``` ## 通过 $parent 获取父组件实例的方法或者属性 从严格意思上讲不是值的传递,而是一种"取"(不推荐直接通过实例进行值的获取)。 可以通过 Vue 的[实例属性](https://cn.vuejs.org/v2/api/#vm-parent)`$parent`获得父组件的实例,借助实例可以调用父实例中的方法,或者获取父实例上的属性,从而达到取值的目的。 ``` // 子组件 ... this.data = this.$parent.sendMessage(); // 调用父实例中的方法 this.msg = this.$parent.msg; // 获取父实例中的属性 ... ``` ## provide(生产者)和inject(注入)-- 深层次嵌套组件传值 ***`provide`和`inject`主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。*** 生产(**provide**)数据,子组件通过注入(**inject**)来消费数据,感觉跟 react 的`React.createContext`很像,一个生产者一个消费者,来跨组件传递数据。 父组件: ```js provide(){ return{ showName:function(){ console.log("父组件数据!!!!!!!!!!!!!!!!"); } } } ``` 任何后代组件: ```js inject: ['showName'], created () { console.log(this.showName()); } ``` > 然而,依赖注入还是有负面影响的。它将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。同时所提供的属性是非响应式的。这是出于设计的考虑,因为使用它们来创建一个中心化规模化的数据跟使用 `$root` 做这件事都是不够好的。 > 如果你想要共享的这个属性是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了。 ## vue 2.4 中`$attrs` 和 `$listeners` # 子向父组件通信 ## 通过事件传值 $emit * 子组件使用`$emit`发送一个自定义事件,事件名称是一个字符串。 * 父组件使用指令`v-on`绑定子组件发送的自定义事件。 ``` // 父组件 List.vue <template> <div> <!-- 监听自定义事件 --> <List-item v-on:welcome="getWelcome"></List-item> </div> </template> <script> import ListItem from "./List-item"; export default { components: { ListItem }, methods: { getWelcome(data) { alert(data) } } } </script> // 子组件 ListItem.vue <template> <button @click="handleClick">Click me</button> </template> <script> export default { methods: { handleClick() { // 使用 $emit 发送自定义事件 welcome this.$emit('welcome', 'hello'); } } } </script> ``` ## 通过 $children 获取子组件实例 此方式同`$parent`...。 ## 通过 ref 注册子组件引用 尽管存在`prop`和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,可以通过`ref`特性为这个子组件赋予一个 ID 引用。 ``` <template> <div> <List-item ref="item" :title="title"></List-item> <div>{{data}}</div> </div> </template> <script> import ListItem from "./List-item"; export default { data() { return { title: "我是title", data: "" } }, components: { ListItem }, mounted() { this.data = this.$refs.item.message; } } </script> ``` [更多 ref 用法](https://cn.vuejs.org/v2/guide/components-edge-cases.html#%E8%AE%BF%E9%97%AE%E5%AD%90%E7%BB%84%E4%BB%B6%E5%AE%9E%E4%BE%8B%E6%88%96%E5%AD%90%E5%85%83%E7%B4%A0) # 兄弟组件通信 ## event bus 非父子组件怎么通过事件进行同步数据,或者同步消息呢? Vue 中的事件触发和监听都是跟一个具体的 Vue 实例挂钩。 所以在不同的 Vue 实例中想进行事件的统一跟踪和触发,那就需要一个公共的 Vue 实例,这个实例就是公共的事件对象。 创建一个公共的 bus,然后导出一个 bus bus.js: ~~~ import Vue from 'vue'; export const bus = new Vue(); ~~~ 然后A B两个组件同时引入 bus.js ~~~ import { bus } from '@/components/bus.js'; ~~~ A 组件 $emit 事件及要传的值 ~~~ getBrother(){ bus.$emit('testEvent','我是要传的值') } ~~~ B组件接收 ~~~ bus.$on('testEvent',val => { console.log(val); this.val = val; }) ~~~ 当然了也可以直接引入 [vue-bus](https://npm.io/package/vue-bus) ~~~ $ yarn add vue-bus $ npm install vue-bus --save ~~~ ---- 借助 `$root`: ``` <script> export default { name: 'Car', methods: { handleClick: function() { this.$root.$emit('clickedSomething') } } } </script> ``` 然后在组件中的生命周期 `mounted` 注册监听事件: ``` <script> export default { name: 'App', mounted() { this.$root.$on('clickedSomething', () => { //... }) } } </script> ``` ## 通过父组件进行过渡 父组件只是充当一个中间媒介,这种方法耦合度高,*不是方法的方法:* 1. 子组件`A`通过事件`$emit`传值传给父组件。 2. 父组件通过属性`props`传值给子组件`B`。 # 其他 官网中提供一个指令[v-slot](https://cn.vuejs.org/v2/guide/components-slots.html),它与`props`结合使用从而达到插槽后备内容与子组件通信的目的。 我们首先需要在子组件的`slot`中传递一个`props`(这个`props`叫做插槽 props),这里我们起名叫`user`: ~~~ <!-- 子组件 current-user.vue --> <template> <div> <div>current-user组件</div> <slot :user="user"> 插槽里默认显示:{{user.firstName}} </slot> </div> </template> ~~~ 在父组件中,包含插槽后备内容的子组件标签上我们绑定一个`v-slot`指令,像这样: ``` <template> <div> <div>我是Users组件</div> <!-- slotProps里的内容就是子组件传递过来的 props --> <!-- "user": { "firstName": "zhao", "lastName": "xinglei" } --> <current-user v-slot="slotProps"> {{ slotProps }} </current-user> </div> </template> ``` 还可以使用 localstorage, Vuex 状态管理库,或者是一些订阅发布的库[pubsub-js](https://npm.io/package/pubsub-js)。 # 跨组件通信 [mitt: 🥊 Tiny 200 byte functional event emitter / pubsub.](https://github.com/developit/mitt) # 参考 [Vue 组件间通信 12 种方法汇总](https://segmentfault.com/a/1190000020796713) [Vue 组件通信方式全面详解](https://libin1991.github.io/2019/02/03/Vue%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1%E6%96%B9%E5%BC%8F%E5%85%A8%E9%9D%A2%E8%AF%A6%E8%A7%A3/)