\ 在 Vue 中,数据通常以单向方式从父组件传递到其子组件。这是通过 props 传递的, props是我们赋予组件的属性或属性。
\ 例如,如果我们调用一个组件PageOne
,它有一个名为name
的 prop,该name
属性将在PageOne
组件本身中变得可用,让我们可以用它做我们想做的事情。这样,当我们在父组件或页面中声明数据时,数据就会向下传递给子组件:
\
\ 在大多数情况下,props 让我们可以对数据做所有需要做的事情。然而,有时我们需要向上发送数据——从子组件到其父组件。为此,我们使用$emit
,它允许我们向上发送数据,然后在触发$emit
事件时在父组件中触发一个事件。
\
$emit
在 Vue 中是如何工作的?
在 Vue 中可以通过三种方式触发$emit
,具体取决于您使用的是 Options API、Composition API 还是内联$emit
事件。
\
- 选项 API 中的
this.$emit
。 - 如果在 HTML 模板中使用
$emit
。 - 如果在 Composition API 中使用,
defineEmits
和emit
。
\让我们通过一个愚蠢的例子来看看它是如何工作的。假设我们有一个计数器组件,如下所示:
\
<template> <button @click="$emit('counterEvent')">Click Me</button> </template>
\ 这个组件存储在一个名为Counter.vue
的文件中。我们的组件无法更改,因为它在其他地方使用,但它确实有一个$emit
事件在任何时候被点击时触发。这是完美的,因为我们可以在父组件中使用它。
\ 那么如果我们想在某个地方添加这个组件——例如,在我们的App.vue
文件中——并使用它来显示我们的计数器的值。现在让我们尝试这样做:
\
<template> <h1></h1> <Counter @counter-event="incrCounter"/> </template> <script> import Counter from './Counter.vue' export default { // Add our components components: { Counter }, // Store our data data() { return { counter: 0 } }, methods: { incrCounter: function() { this.counter += 1; } } } </script>
\ 让我们分解一下——首先,我们包括我们的Counter
。由于有一个名为counterEvent
的$emit
事件,我们可以将它附加到Counter
HTML 中。每当$emit
触发时,它都会触发counterEvent
,从而触发该属性中的函数。在这里,每当counterEvent
触发时,我们都会运行incrCounter
。
\ 通过这样做,我们还可以将counter
数据增加 1,因为这就是incrCounter
所做的。因此,我们已经将 click 事件向上发送到我们的父组件。
\
为什么我们使用 Kebab Case?
您可能会注意到,当我们定义$emit
事件时,我们使用了驼峰式 ( counterEvent
),但在跟踪事件时,我们使用了烤肉式 ( counter-event
)。
\ 在Vue 3中,可以互换使用counterEvent
和counter-event
,因为 Vue 3 会自动将counterEvent
转换为counter-event
。在Vue 2中,此功能不存在,因此只需对两者都使用counter-event
。
\
使用$emit
传递数据
假设相反,我们希望我们的组件定义counterEvent
应该增加多少。如果我们想这样做,我们可以将第二个参数传递给$emit
函数,它是值:
\
<template> <button @click="$emit('counterEvent', 2)">Click Me</button> </template>
\在这里,我们将值2
传递给我们的counterEvent
。让我们回到我们的App.vue
文件。为了在counterEvent
中利用这个值,我们需要把它写成一个函数。下面, n
是值:
\
<template> <h1></h1> <Counter @counter-event="(n) => incrCounter(n)"/> </template> <script> import Counter from './Counter.vue' export default { // Add our components components: { Counter }, // Store our data data() { return { counter: 0 } }, methods: { incrCounter: function(value) { this.counter += value; } } } </script>
\ 现在,我们的计数器将增加放入子组件中的值,允许我们也将数据传递给父组件。如您所料,这不仅限于数字,还可以包括任何数据结构——包括对象和字符串。
\
将$emit
与选项 API 一起使用
我们已经展示了一个非常简单的示例,但我们也可以使用函数来编写Counter.vue
子组件。这是一个使用选项 API的示例,使用this.$emit
:
\
<template> <button @click="emitFunction">Click Me</button> </template> <script> export default { emits: [ 'counterEvent' ], methods: { emitFunction: function() { this.$emit('counterEvent', 2) } } } </script>
\ 这可能被证明是使用$emit
的一种更简洁的方式,特别是如果您想在单击按钮时使用$emit
做其他事情。
\
将您的发射事件添加到您的原型
你可能注意到我们还在原型的emits
中定义了我们的 emit 事件。这是一个很好的做法,原因有两个:
- 它允许您通过显示该组件中可能发生的发射事件来对代码进行自我记录。
- 它可以帮助您跟踪已弃用的 emits ,因为如果使用了 emit 事件但在
emits
数组中找不到,Vue 会抛出错误。
\
将$emit
与 Composition API 一起使用
我们可以将$emit
与 Composition API 一起使用——唯一的区别是我们必须使用defineEmits
来代替。
\
<template> <button @click="emitFunction">Click Me</button> </template> <script setup> import { defineEmits } from 'vue' const emit = defineEmits(['counterEvent']); const emitFunction = function() { emit('counterEvent', 2) } </script>
\ defineEmits
用于定义所有允许的emit
事件的完整列表。在这里,我们只有一个counterEvent
。如果你有多个,你可以这样定义它们:
\
const emit = defineEmits(['counterEvent', 'anotherEvent', 'finalEvent']);
\ 如果你使用了未在defineEmits
中列出的 emit 事件,Vue 会抛出一个警告,类似于在 Options API 上使用emits
。否则,您可以像往常一样使用emit()
函数发出,而根本不需要使用Options API 。
\
最后的想法和最佳实践
Emit 是一个强大的工具,可以在需要时将数据发送回父级。这意味着数据流在 Vue 中可以是双向的。在定义emit
代码时,两个主要的最佳实践是:
- 始终在
emits
或defineEmits
中定义您的 emit 事件,这将帮助您保持代码清洁和有据可查。 - Vue 3 中的常规约定是对 HTML 使用 kebab 大小写 (
this-is-kebab-case
),在脚本中使用骆驼大小写 (thisIsCamelCase
)。因此,最好也遵循此约定。
\
\ 我希望你喜欢这个关于$emit
如何工作的指南。请继续关注更多Vue 内容。
也在这里发布
原文: https://hackernoon.com/learn-how-to-emit-custom-events-in-vue-with-$emit?source=rss