跳至内容

事件处理

Vue 组件通过 props 和通过调用 $emit 发射事件来相互交互。在本指南中,我们将了解如何使用 emitted() 函数验证事件是否正确发射。

本文也以 简短视频 的形式提供。

计数器组件

这是一个简单的 <Counter> 组件。它包含一个按钮,当点击该按钮时,会递增内部计数变量并发射其值

js
const Counter = {
  template: '<button @click="handleClick">Increment</button>',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count += 1
      this.$emit('increment', this.count)
    }
  }
}

为了完全测试此组件,我们应该验证是否发射了带有最新 count 值的 increment 事件。

断言发射的事件

为此,我们将依赖 emitted() 方法。它 **返回一个包含组件发射的所有事件的对象**,以及它们的参数(以数组形式)。让我们看看它是如何工作的

js
test('emits an event when clicked', () => {
  const wrapper = mount(Counter)

  wrapper.find('button').trigger('click')
  wrapper.find('button').trigger('click')

  expect(wrapper.emitted()).toHaveProperty('increment')
})

如果您以前没有见过 trigger(),不用担心。它用于模拟用户交互。您可以在 表单 中了解更多信息。

首先要注意的是 emitted() 返回一个对象,其中每个键都与一个发射的事件匹配。在本例中,是 increment

此测试应该通过。我们确保发射了具有适当名称的事件。

断言事件的参数

这很好 - 但我们可以做得更好!我们需要检查当调用 this.$emit('increment', this.count) 时,我们是否发射了正确的参数。

我们的下一步是断言该事件包含 count 值。我们通过将参数传递给 emitted() 来做到这一点。

js
test('emits an event with count when clicked', () => {
  const wrapper = mount(Counter)

  wrapper.find('button').trigger('click')
  wrapper.find('button').trigger('click')

  // `emitted()` accepts an argument. It returns an array with all the
  // occurrences of `this.$emit('increment')`.
  const incrementEvent = wrapper.emitted('increment')

  // We have "clicked" twice, so the array of `increment` should
  // have two values.
  expect(incrementEvent).toHaveLength(2)

  // Assert the result of the first click.
  // Notice that the value is an array.
  expect(incrementEvent[0]).toEqual([1])

  // Then, the result of the second one.
  expect(incrementEvent[1]).toEqual([2])
})

让我们回顾一下并分解 emitted() 的输出。这些键中的每一个都包含在测试期间发射的不同值

js
// console.log(wrapper.emitted('increment'))
;[
  [1], // first time it is called, `count` is 1
  [2] // second time it is called, `count` is 2
]

断言复杂事件

想象一下,现在我们的 <Counter> 组件需要发射一个包含附加信息的 Object。例如,我们需要告诉任何监听 @increment 事件的父组件 count 是偶数还是奇数

js
const Counter = {
  template: `<button @click="handleClick">Increment</button>`,
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count += 1

      this.$emit('increment', {
        count: this.count,
        isEven: this.count % 2 === 0
      })
    }
  }
}

与之前一样,我们需要触发 <button> 元素上的 click 事件。然后,我们使用 emitted('increment') 来确保发射了正确的 value。

js
test('emits an event with count when clicked', () => {
  const wrapper = mount(Counter)

  wrapper.find('button').trigger('click')
  wrapper.find('button').trigger('click')

  // We have "clicked" twice, so the array of `increment` should
  // have two values.
  expect(wrapper.emitted('increment')).toHaveLength(2)

  // Then, we can make sure each element of `wrapper.emitted('increment')`
  // contains an array with the expected object.
  expect(wrapper.emitted('increment')[0]).toEqual([
    {
      count: 1,
      isEven: false
    }
  ])

  expect(wrapper.emitted('increment')[1]).toEqual([
    {
      count: 2,
      isEven: true
    }
  ])
})

测试 Object 等复杂事件有效负载与测试数字或字符串等简单值没有什么不同。

组合 API

如果您使用的是组合 API,您将调用 context.emit() 而不是 this.$emit()emitted() 会捕获来自两者的事件,因此您可以使用此处描述的相同技术来测试您的组件。

结论

  • 使用 emitted() 访问从 Vue 组件发射的事件。
  • emitted(eventName) 返回一个数组,其中每个元素代表一个发射的事件。
  • 参数存储在 emitted(eventName)[index] 中,以数组形式存储,顺序与它们发射的顺序相同。