If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
Many Vue patterns involve using props
to pass data from parent components to child components. But what if we need a child component to pass data to its parent?
Using emit
, we can fire events and pass data down a hierarchy of components. This is useful in situations such as:
- emit data from input
- Close the modal from within the modal itself
- Parent component responds to child component
How does Vue Emit work?
When we emit an event, we call a method with one or more arguments:
- eventName: string - the name of the event
- values: any - parameters passed through the event
Here is an example of an inline emit, <button @click="$emit('add', Math.random())">
. Emit an event named add
and pass the value of Math.random()
as a parameter.
Then, use the v-on
or @
instruction in the parent component to listen to our custom add event and receive the parameter value.
Child.vue
<template>
<button @click="$emit('add', Math.random())">
Add Math.random()
</button>
</template>
Listen in Parent.vue :
<script setup>
import { ref } from 'vue'
const count = ref(0)
// 也可以从我们的模板中调用一个函数 `<ChildComponent @add="add" />
// const add = (i) => count.value += i
</script>
<template>
<ChildComponent @add="(i) => count += i" />
<p>Count: {{ count }}</p>
</template>
Every time we click the button, Child.vue
will emit a add
event with a random value between 0 and 1. Then, Parent.vue
catches this event and adds this value to the count.
You can pass as many parameters as you want, and the listener will also receive all of them:
- Child -
$emit('add', Math.random(), 44, 50)
- Parent -
@add="(i, j, k) => count += i + j + k"
Now, we know how to emit inline events in our templates, but in a more complex example, it would be better if we emitted an event from the SFC's script
. This is useful especially when we want to execute some logic before the emit event.
In Vue 3 we have 2 different ways to do this:
- Options API
this.$emit
- Combined API with
setup()
-context.emit
- Combined API with
<script setup>
-defineEmits()
Let's look at them one by one.
Options API -- this.$emit
In Vue3, I can choose to use the options API or the composition API.
In the options API, we can call this.$emit
to emit a custom event.
Look at the example below in MyTextInput.vue
which contains a label
and input
. Whenever input
changes, we will emit an event and pass the input value to uppercase as a parameter.
Instead of calling $emit
from the template, we can call a component method. In this method call this.$emit
and pass it our value.
MyTextInput.vue
<script>
export default {
methods: {
handleChange (event) {
this.$emit("customChange", event.target.value.toUpperCase())
}
}
}
</script>
<template>
<div>
<label>My Custom Input</label>
<input type="text" placeholder="Custom input!" @input="handleChange" />
</div>
</template>
Receive in Parent.vue :
<script>
export default {
methods: {
handleChange (event) {
this.$emit("customChange", event.target.value.toUpperCase())
}
}
}
</script>
<template>
<div>
<label>My Custom Input</label>
<input type="text" placeholder="Custom input!" @input="handleChange" />
</div>
</template>
Combined API with setup()
- context.emit
In the combined API, if you use the setup
function, you cannot use the this
method, that is, you cannot call the this.$emit()
method.
Instead, the context
emit
. We can call context.emit
with the event name and value we used earlier.
MyTextInput.vue
<script>
export default {
// can use the entire context object
setup (props, context) {
const handleChange = (event) => {
context.emit("customChange", event.target.value)
}
return {
handleChange
}
},
// or we can destructure it and get `emit`
setup (props, { emit }) {
const handleChange = (event) => {
emit("customChange", event.target.value)
}
return {
handleChange
}
}
}
</script>
<template>
<div>
<label>My Custom Input</label>
<input type="text" placeholder="Custom input!" @input="handleChange" />
</div>
</template>
Usage in <script setup>
When we use <script setup>
, we cannot access the component instance or context
context parameter. So how do we get emit
?
In this case we can use defineEmits
:
- Specify the component to emit the event
- Add validation information for each event
- Can access the same value as context.emit
In the simplest case, defineEmits
is an array of strings, each string being the name of an event.
MyTextInput.vue
<script setup>
const emit = defineEmits(['customChange'])
const handleChange = (event) => {
emit('customChange', event.target.value.toUpperCase())
}
</script>
However, if we pass an object, we can add a validator function to each event where we can check if the value is in the format we want.
Like event listeners, validators accept all the parameters we pass in.
This is similar to prop validation, if our validator returns false
, we get a warning in the console, which gives us some useful information.
MyTextInput.vue
<script setup>
const emit = defineEmits({
unvalidatedEvent: null, // if we want an event without validation
customChange: (s) => {
if (s && typeof s === 'string') {
return true
} else {
console.warn(`Invalid submit event payload!`)
return false
}
},
})
const handleChange = (event) => {
// no console warning
emit('customChange', event.target.value.toUpperCase())
}
onMounted(() => {
emit('customChange', 1) // not a string, warning!
})
</script>
Best Practices
Use emits to define custom events.
If we don't use defineEmits
, we can still track a component's custom events by defining the export default
emits
option in ---c33036d9dab53afa6facad658731ae8a---.
This is important to maintain good component documentation, and we will also get errors from Vue if we try to use an event that is not declared in emits.
When a native event (such as change) is defined in the emits option, the event in the component will be used instead of the native event listener.
<script>
export default {
emits: ["change"] // or can pass object with validators
}
</script>
<template>
<div>
<label>My Custom Input</label>
<input
type="text"
placeholder="Custom input!"
@input='$emit("change", $event.target.value)'
/>
</div>
</template>
correct event command
In vue3, like components and props, event names provide automatic case conversion. If you fire a camelCase (camel case) event in the child component, you will be able to add a kebab-case (dash-separated name) listener to the parent component.
However, if you are using Vue 2, there is no automatic case conversion for event names, since the v-on
directive will automatically convert your event names to lowercase, so events named camelCase cannot be listened to.
For example, if we emit an event named myEvent
, listening for my-event
will not work.
The bugs that may exist in editing cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, here is a useful BUG monitoring tool , Fundebug .
Author: Noveo Translator: Xiaozhi Source: learnvue
Original: https://learnvue.co/tutorals/vue-emit-guide
comminicate
If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。