35

使用事件总线共享组件之间的Props

 5 years ago
source link: https://www.w3cplus.com/vue/using-event-bus-to-share-props-between-vue-components.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

特别声明,本文根据 @KINGSLEY SILAS 的《 Using Event Bus to Share Props Between Vue Components 》一文所整理。

默认情况下,Vue组件之间的通讯是通过 Props 来完成的。 Props 是从父组件向子组件传递属性。例如,这里有一个组件, title 是一个 prop :

<blog-post title="My journey with Vue"></blog-post>

Props 总是从父组件向子组件传递。随着应用程序复杂度的增加,你会慢慢遇到所谓的 Prop Drilling ,这里有 一篇文章 介绍了这方面的东西,虽然是React方面的,但也适用于Vue。Prop Drilling是将 props 向下、向下、向下传递给子组件的想法 —— 正如你想象的那样,这通常是一个乏味的过程。

因此,繁琐的Prop Drilling可能是一个复杂的潜在问题。另一个与不相关的组件之间的通讯有关。我们可以通过使用 事件总线 来解决这些问题。

什么是事件总线?这个名字本身就是一个总结。这是一个组件将 props 从一个组件传递到另一个组件的一种运输方式,无论这些组件伴于树的哪个位置。

练习任务:建立一个计数器

让我们一起构建一些东西,用来帮助我们演示事件总线相关的概念。一个计数器,增加或减少 input 中输入的数值,并记录总数。

为了使用事件总线,我们首先需要对事件总线进行初始化。可以在 src 下创建一个 event-bus.js 文件,添加下面这段代码,对事件总线进行初始化:

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

除了像上面那样对事件进行初始化之外,还可以对事件总线进行全局初始化。有关于这方面的详细介绍,可以阅读前段时间整理的一篇文章《 Vue 2.0学习笔记:事件总线(EventBus) 》。

这里将 Vue 实例设置为 EventBus 。当然,你也可以随便给它起一个你喜欢的名字。如果你使用的是一个 单文件组件 ,那么你应该在一个单独的文件中添加下面这段代码,因为无论如何你都必须导出( export )分配给 EventBusVue 实例。

import Vue from 'vue';
export const eventBus = new Vue();

这样我们就可以在计数器组件( Counter )中使用它了。不过在上面的示例中,为 EventBus 初始化单独创建了一个 event-bus.js ,在这个文件中添加了初始化 EventBus 的代码。在 Counter 组件可以像下面这样调用已初始化的 EventBus

<!-- Counter.vue -->
import { EventBus } from "../event-bus.js";

接下一我们要做的是:

  • 我们想要一个初始值为 0count
  • 我们需要一个接受数值的输入框 input
  • 我们需要两个按钮 button :一个在单击时将提交的数值添加到计数( count )中,另一个将在单击时从计数中减去提交的数值
  • 我们想确认当计数改变时发生了什么

我们在 Counter 中的模板可以这样写:

<!-- Counter.vue -->
<template>
    <div class="counter">
        <h3>{{ count }}</h3>
        <div :class="$style.form">
            <button @click.prevent="handleIncrement" :class="[$style.btn, $style['btn-increment']]">+</button>
            <input type="number" v-model="entry" :class="$style.input" />
            <button @click.prevent="handleDecrement" :class="[$style.btn, $style['btn-decrement']]">-</button>
        </div>
        <div class="form-help">{{ text }}</div>
    </div>
</template>

通过 v-modelentry 的值绑定到 input ,根据用户输入的内容,我们将使用该值来增加或减少计数。当单击任何一个按钮时,都会触发一个方法,该方法会增加或减少 count 的值。最后,在 <p> 标签中包含的 {{ text }} 会打印出提示消息(当 count 值更改后)。

以下是 Counter 组件对应的脚本代码:

<!-- Counter.vue -->
<script>
    import { EventBus } from "../event-bus.js";
    export default {
        name: "Counter",
        data() {
            return {
                count: 0,
                entry: 3,
                text: ''
            };
        },
        created () {
            EventBus.$on('count-incremented', () => {
                this.text = `Count was increased`
                setTimeout(() => {
                    this.text = ''
                }, 3000)
            })

            EventBus.$on('count-decremented', () => {
                this.text = `Count was decreased`
                setTimeout(() => {
                    this.text = ''
                }, 3000)
            })
        },
        methods: {
            handleIncrement () {
                this.count += parseInt(this.entry, 10)
                EventBus.$emit('count-incremented')
                this.entry = 0
            },
            handleDecrement () {
                this.count -= parseInt(this.entry, 10)
                EventBus.$emit('count-decremented')
                this.entry = 0
            }
        }
    };
</script>

我们要做的第一件事是建立一个从一个组件发送事件到另一个组件的路径。我们可以使用 EventBus.$emit() (通过 $emit() )来铺路。这种发送包含在两个方法中, handleIncrementhandleDecrement ,这两个方法用来监听 input 的提交。一旦事件发生,我们的事件总线就会向任何请求数据的绷件发送 Props

baeMJ3E.png!web

你可能已经注意到,我们正在使用 EventBus.$on()created() 钩子中侦听这两个事件。在这两个事件中,我们必须传递与我们发出的事件相对应的字符串。这类似于特定事件的标识符,以及为组件建立接收数据方式的标识符。当 EventBus 识别已宣布的特定事件时,接下来的函数将被调用 —— 我们设置一个文本来显示发生了什么,并在三秒钟后使其消失。

练习任务:处理多个组件

假设我们正在开发一个配置文件页面,用户可以在该页面上更新自己的名字和电子邮件地址,然后在不刷新页面的情况下查看更新。即使我们要处理两个组件,也可以使用事件总线来实现这个效果。

在上面的这个示例中,我们创建了 ShowProfileEditProfile 两个组件,前者用来显示个人信息,后者用来编辑个人信息。两个组件的 <template> 分别如下:

<!-- ShowProfile.vue -->
<template>
    <div :class="$style.profile">
        <h1>{{ name }}</h1>
        <p>{{ email }}</p>
    </div>
</template>

<!-- EditProfile.vue -->
<template>
    <div :class="$style['edit-profile']">
        <h3>Enter your details below</h3>
        <form @submit.prevent="handleSubmit">
            <div :class="$style['form-controle']">
                <label for="name">Name</label>
                <input type="text" v-model="user.name" id="name" />
            </div>
            <div :class="$style['form-controle']">
                <label for="email">Email</label>
                <input type="email" v-model="user.email" id="email" />
            </div>
            <div :class="$style['form-controle']">
                <button>Submit</button>
            </div>
        </form>
    </div>
</template>

我们把 idsuser.nameuser.email )传递相应的组件。首先,让我们为 EditProfile 组件设置模板,它包含我们想要传递给 ShowProfile 组件的 nameemail 数据。同样,我们也和前面的示例一样,创建了一个事件总线,在它监听到 submit 事件后发出该数据。

<!-- EditProfile.vue -->
<script>
    import { EventBus } from "../event-bus.js";
    export default {
        name: "EditProfile",
        data() {
            return {
                user: {
                    name: "",
                    email: ""
                }
            };
        },
        methods: {
            handleSubmit() {
                EventBus.$emit("form-submitted", this.user);
                this.user = {};
            }
        }
    };
</script>

ShowProfile 组件中的 data 主要用于用户提交数据时, ShowProfile 中的 data 进行反应性(Reactively)更新,该组件查找事件总线到达其集线器时输入的 nameemail

<!-- ShowProfile.vue -->
<script>
    import { EventBus } from "../event-bus.js";
    export default {
        name: "ShowProfile",
        data() {
            return {
                name: "W3cplus",
                email: "[email protected]"
            };
        },
        created() {
            EventBus.$on("form-submitted", ({ name, email }) => {
                this.name = name;
                this.email = email;
            });
        }
    };
</script>

很酷,对吧!尽管 ShowProfileEditProfile 组件是兄弟关系(不是直接的父子关系),但是它们可以通过相同的事件进行数据通讯。

总结

事件总线想在应用程序中激活反应的情况下是很有帮助的。具体来说,就是从服务器获得向应更新组件,而不会导致页面刷新。还可能有多个组件可以侦听发出的事件。如果你有其他关于使用事件总线的有趣场景,欢迎在下面的评论中与我们共享。

扩展阅读


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK