Skip to content

事件处理

¥Event Handling

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

¥Vue components interact with each other via props and by emitting events by calling $emit. In this guide, we look at how to verify events are correctly emitted using the emitted() function.

本文也可作为 短视频 提供。

¥This article is also available as a short video.

计数器组件

¥The Counter component

这是一个简单的 <Counter> 组件。它有一个按钮,单击该按钮会增加内部计数变量并触发其值:

¥Here is a simple <Counter> component. It features a button that, when clicked, increments an internal count variable and emits its value:

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 事件。

¥To fully test this component, we should verify that an increment event with the latest count value is emitted.

断言触发的事件

¥Asserting the emitted events

为此,我们将依靠 emitted() 方法。它返回一个对象,其中包含组件已触发的所有事件及其数组中的参数。让我们看看它是如何工作的:

¥To do so, we will rely on the emitted() method. It returns an object with all the events the component has emitted, and their arguments in an array. Let's see how it works:

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(),请不要担心。它用于模拟用户交互。你可以在 表单 中了解更多信息。

¥If you haven't seen trigger() before, don't worry. It's used to simulate user interaction. You can learn more in Forms.

首先要注意的是 emitted() 返回一个对象,其中每个键都匹配一个触发的事件。在这种情况下,increment

¥The first thing to notice is that emitted() returns an object, where each key matches an emitted event. In this case, increment.

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

¥This test should pass. We made sure we emitted an event with the appropriate name.

断言事件的参数

¥Asserting the arguments of the event

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

¥This is good - but we can do better! We need to check that we emit the right arguments when this.$emit('increment', this.count) is called.

我们的下一步是断言该事件包含 count 值。我们通过向 emitted() 传递一个参数来实现这一点。

¥Our next step is to assert that the event contains the count value. We do so by passing an argument to 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() 的输出。每个键都包含测试期间触发的不同值:

¥Let's recap and break down the output of emitted(). Each of these keys contains the different values emitted during the test:

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

断言复杂事件

¥Asserting complex events

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

¥Imagine that now our <Counter> component needs to emit an object with additional information. For instance, we need to tell any parent component listening to the @increment event if count is even or odd:

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') 确保触发正确的值。

¥As we did before, we need to trigger the click event on the <button> element. Then, we use emitted('increment') to make sure the right values are emitted.

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
    }
  ])
})

测试复杂的事件负载(例如对象)与测试简单的值(例如数字或字符串)没有什么不同。

¥Testing complex event payloads such as Objects is no different from testing simple values such as numbers or strings.

合成 API

¥Composition API

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

¥If you are using the Composition API, you will be calling context.emit() instead of this.$emit(). emitted() captures events from both, so you can test your component using the same techniques described here.

结论

¥Conclusion

  • 使用 emitted() 访问从 Vue 组件触发的事件。

    ¥Use emitted() to access the events emitted from a Vue component.

  • emitted(eventName) 返回一个数组,其中每个元素代表触发的一个事件。

    ¥emitted(eventName) returns an array, where each element represents one event emitted.

  • 参数按照触发的顺序存储在数组中的 emitted(eventName)[index] 中。

    ¥Arguments are stored in emitted(eventName)[index] in an array in the same order they are emitted.

Vue Test Utils 中文网 - 粤ICP备13048890号