Update 2022
The useContext and getCurrentInstance APIs were deprecated and are no longer exposed to the Vue 3 API. Instead of that, you should use the defineEmits at the root level on the setup script.
<template>
<button @click="action('')"></button>
</template>
<script setup>
const emit = defineEmits(['close', 'unClose'])
const action = (id) => emit('close', val);
</script>
and for typescript the definition would be:
const emit = defineEmits<{
(e: 'close', val: string): void
(e: 'unClose', id: number): void
}>()
Outdated, Pre-Vue 3.2
- You don't need to define emit at all to run
$emit from the template
useContext provides the emit function for use in setup function
- using
defineEmits adds the list of emits to the component (equivalent to emits: definition of component) but doesn't help with the emit
useContext
<template>
<button @click="action('')"></button>
<!-- emit is defined through useContext -->
<button @click="emit('action1','')">1</button>
<!-- $emit here doesn't need to be defined -->
<button @click="$emit('action2','')">2</button>
</template>
<script setup>
import { defineProps, useContext } from 'vue'
const { emit } = useContext()
const action = (id) => emit('action', id);
</script>
Note that vetur extension might tell you that it's deprecated and that you should use useSlots and useAttrs instead. If you want to use emit from the script, those, obviously, won't help with that.
getCurrentInstance
import { defineProps, getCurrentInstance} from 'vue'
const { emit } = getCurrentInstance()
In addition to running an emit, vue3 allows (recommends♂️) that the emits are defined, so the component parent might know what events a component might emit. To do that using the <script setup> form, you can use defineEmit
<script setup>
import { defineEmit } from 'vue'
const emit = defineEmit(['action'])
const action = (id) => emit('action', id);
</script>
This will allow sending action emit event, but if you emit a doit although it will still emit, you'll get a warning in the console
[Vue warn]: Component emitted event "doit" but it is neither declared in the emits option nor as an "onDoit" prop.