Vue 3 define Macros

📢 This article was translated by gemini-3-flash-preview

Defining Options API Options

Vue 3.3 introduced the defineOptions() macro. It allows you to define Options API options (like name) without needing a separate script block, excluding props, emits, expose, and slots (which have their own dedicated define macros).

1
2
3
4
5
6
<script setup>
defineOptions({
    name: 'LoginIndex',
    // ...
})
</script>

Why use name?

  • Debugging: The component name shows up in Vue DevTools.
  • Recursive Components: Allows a component to call itself using its name.
  • <keep-alive>: Enables filtering which components to cache using include or exclude.

Two-Way Binding Between Parent and Child

Implementing two-way data binding used to be a bit verbose.

In the parent component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script setup>
import { ref } from 'vue';
import inputCom from './components/input-com.vue';

const msg = ref("a msg from father")
</script>

<template>
    <inputCom v-model="msg"></inputCom>
    <div>{{ msg }}</div>
</template>

In the child component (the old way):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<script setup>
defineProps({
    modelValue: String
})

const emit = defineEmits(['update:modelValue'])
</script>

<template>
    <div>
        <input
          type="text"
          :value="modelValue"
          @input="e => emit('update:modelValue', e.target.value)"></input>
    </div>
</template>

With the defineModel() macro, it becomes much cleaner. The child component can be refactored to:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<script setup>
const modelValue = defineModel()
</script>

<template>
    <div>
          <input
          type="text"
          :value="modelValue"
          @input="e => modelValue = e.target.value"></input>
    </div>
</template>
This post is licensed under CC BY-NC-SA 4.0 by the author.