用于孩子与家长沟通的 Vue.js 事件

我们已经看到 props 用于将数据从父组件传递到子组件。

为了将数据从子组件传递回父组件,Vue.js 具有自定义事件。

在组件中,可以使用 $emit 实例方法发出事件。它可以在脚本部分中使用 this.$emit('eventName', /* Payload */) 来使用,但它也在模板(template)部分中作为 $emit 公开。

假设我们有一个响应式实例属性 this.message,我们可以使用 this.$emit 在脚本部分中发出带有消息值的发送(send)事件。这可能是 MessageEditor 组件的基础:

<script>
export default {
    data () {
        return {
            message: null
        }
    },
    methods: {
        send() {
            this.$emit('send', this.message);
        }
    }
}
</script>

在相同的场景中,我们可以从模板(template)部分触发发送(send)事件:

<template>
    <div>
        <input v-model="message" />
        <button @click="$emit('send', message)">Emit inline</button>
    </div>
</template>

在父组件中,我们可以使用 v-on:event-name 或简写 @event-name.event-name 必须与传递给 $emit 的名称匹配; eventName 和 event-name 不相等。

例如,父组件将是我们如何使用 @send 监听发送(send)事件并保存 $event 魔术值中包含的事件负载。要在方法调用中使用事件负载,我们可以使用 @eventName="methodToCall($event)":

<template>
    <div id="app">
        <p>Message: {{ message }}</p>
        <MessageEditor @send="message = $event" />
        <button @click="message = null">Reset</button>
    </div>
</template>

<script>
import MessageEditor from './components/MessageEditor.vue'

export default {
    components: {
        MessageEditor
    },
    data() {
        return {
            message: null
        }
    }
}
</script>

使用 $emit 的内联版本和方法版本会产生相同的结果。完整的 MessageEditor 应用程序应如下所示:

image 2023 10 13 16 52 37 317
Figure 1. Figure 4.32: Hello World! message being emitted from child-parent

Vue.js 自定义事件支持传递任何 JavaScript 类型作为有效负载。但是,事件名称必须是字符串。

将侦听器绑定到 Vue.js 自定义事件与绑定到本机事件(例如单击)非常相似。

现在,让我们根据目前所学到的知识来完成一项活动。

活动 4.01:具有可重用组件的本地消息视图

此活动旨在利用组件、props、事件和 refs 来渲染聊天界面,用户可以在其中添加消息并显示它们。

请按照以下步骤完成此活动:

  1. 创建一个向用户显示文本区域的 MessageEditor 组件(在 src/components/ MessageEditor.vue 中)。

  2. 给 MessageEditor 添加一个消息响应实例变量,默认为 ''

  3. 监听 textarea 的 change 事件,并将 message 的值设置为 textarea 内容的值(作为事件的值公开)。

  4. 添加一个 Send 按钮,单击该按钮会发出一个以消息作为有效负载的发送事件。

  5. 在 src/App.vue 中添加一个主要的 App 组件来渲染 MessageEditor。

  6. 在 App 中,侦听来自 MessageEditor 的发送(send)事件,并将每条消息存储在 messages 响应实例变量中(messages 是一个数组)。

  7. 创建一个 MessageFeed(在 src/components/MessageFeed.vue 中),它具有必需的 messages 属性,它是一个数组。

  8. 在 MessageFeed 中,在段落(p 元素)中渲染来自 messages 属性的每条传递的消息。

  9. 将 MessageFeed 导入并渲染到 App 中,将 messages app 实例变量绑定为 MessageFeed 的 messages 属性。

  10. 改进 MessageEditor ,使消息发送时重置。 为此,我们需要使用 Vue.js 引用设置 textarea.value 并重置 message 实例变量。

重置 textarea 的更简单方法是首先使用 v-model="message",而不是绑定 @change 并手动将 textarea.value 同步到 message。

预期输出如下:

image 2023 10 13 17 09 35 370
Figure 2. Figure 4.33: Message app with Hello World! and Hello JavaScript sent

总结

在本章中,我们学习了 Vue.js 原语,它们允许我们以高效组合的方式构建组件。

Props 和 slot 用于将组件内的行为推迟到渲染它们的父组件。 Props 具有可验证的能力,非常适合将数据传递到嵌套组件中。 插槽旨在将渲染控制权交还给父组件。 事件使子组件能够将数据发送回其父组件,从而完成父子通信周期(props 向下,事件向上)。

全局模板助手可以封装在过滤器中,以减少样板文件并增加代码重用。 Refs 允许我们直接访问 DOM 元素,从而具有与第三方 JavaScript 或 DOM 库集成的机会。

我们现在能够编写和创建组件,这些组件可以清楚地定义其与输入(propsslots)和输出(渲染模板和事件)的接口,同时还可以访问常见的用例(包装 DOM 库、在过滤器中抽象模板关注点等等)。

在下一章中,我们将研究高级组件组合模式和技术,以实现更好的代码重用。