Appearance
事件处理
¥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.