• 开始时间:2019-02-27
  • 目标主要版本:2.x 和 3.x
  • 引用 issue:N/A
  • 实现的 PR:N/A

摘要

明确说明组件抛出的事件是什么。

基本范例

  1. const Comp = {
  2. emits: {
  3. submit: payload => {
  4. // validate payload by returning a boolean
  5. }
  6. },
  7. created() {
  8. this.$emit('submit', {
  9. /* payload */
  10. })
  11. }
  12. }

动机

  • 文档:props 类似,明确的 emits 声明可以作为自我记录的代码。这对于其他开发者来说是非常有用的,他们可以立即了解该组件应该抛出什么事件。
  • 运行时验证:该选项还提供了一种方法,对抛出的事件载荷(参数)进行运行时验证。
  • 类型推断:emits 选项可以用于提供类型推断,以便 this.$emitsetupContext.emit 调用可以被类型化。
  • IDE 支持:当在组件上使用 v-on 监听器时,IED 可以利用 emits 选项来提供自动补全。
  • 监听器 fallthrough 控制:随着提案的属性 fallthrough 更改,组件上的 v-on 监听器将默认为原生监听器。emits 提供了一种声明事件为组件专用的方法,以避免不必要的原生监听器的注册。

具体设计

引入了一个新的可选组件选项,名为 emits

数组语法

对于简单的用例,选项值可以是一个包含字符串事件名称的数组:

  1. {
  2. emits: [
  3. 'eventA',
  4. 'eventB'
  5. }
  6. }

对象语法

或者它可以是一个以事件名称为 key 的对象。每个属性的值可以是 null,也可以是一个验证函数。验证函数将接收传递给 $emit 调用的额外参数。例如,如果 this.$emit("foo", 1, 2) 被调用,foo 的相应验证函数将接收参数 1 和 2。验证函数应该返回一个布尔值来表示事件参数是否有效。

  1. {
  2. emits: {
  3. // no validation
  4. click: null,
  5. // with validation
  6. //
  7. submit: payload => {
  8. if (payload.email && payload.password) {
  9. return true
  10. } else {
  11. console.warn(`Invalid submit event payload!`)
  12. return false
  13. }
  14. }
  15. }
  16. }

fallthrough 控制

#154 中提出的新的属性 fallthrough 行为现在适用于组件上使用 v-on 监听器的自动 fallthrough:

  1. <Foo @click="onClick" />

为了向后兼容,我们没有要求 emits 通过组件抛出的事件来触发 click。因此在上面的例子中,如果没有 emits 选项,监听器可以被 Foo 的根元素的原生 click 事件或 Foo 发出的自定义事件所触发。

然而,如果通过使用 emits 选项将 click 声明为一个自定义事件,那么它将只被自定义事件触发,而不再作为一个原生监听器 fallthrough。

emits 声明的事件监听器也被排除在组件的 this.$attrs 之外。

类型推导

对象验证器的语法是在考虑 TypeScript 类型推导的情况下选择的。验证器的类型签名可以用于类型 $emit 调用。

  1. const Foo = defineComponent({
  2. emits: {
  3. submit: (payload: { email: string; password: string }) => {
  4. // perform runtime validation
  5. }
  6. },
  7. methods: {
  8. onSubmit() {
  9. this.$emit('submit', {
  10. email: 'foo@bar.com',
  11. password: 123 // Type error!
  12. })
  13. this.$emit('non-declared-event') // Type error!
  14. }
  15. }
  16. })

缺点

  • 该选项需要对所有发出的自定义事件的组件付出一些额外的精力。然而,它在技术上是可选的,其好处应该超过所需要的额外精力。
  • 运行时验证应该只在开发模式下进行,但有可能会使得生产环境的包的大小增加。Props 验证器也有同样的问题。这两个问题都可以通过一个 Babel 插件来解决,该插件可以在生产构建中把 propsemits 转换为 Array 格式。这样一来,只有开发模式的代码被剥离,但运行时的行为将保持一致。

备选方案

N/A

采纳策略

emits 选项的引入不应该破坏 $emit 的任何现有用法。

然而,随着 fallthrough 行为的改变,最理想的做法是始终声明抛出的事件。我们可以:

  1. 提供一个 codemod,自动扫描组件中所有 $emit 调用的实例并生成 emits 选项。
  2. (Opt-in)当一个抛出的事件没有使用选项声明时,抛出一个运行时警告。

没有解决的问题

N/A