為了讓 Component 的 Reusability 更高,我們不會將呼叫 API 部分寫在 Component 內,而會將呼叫 API 部分寫在 Component 外部,如此我們必須從 Component 內傳出 Data。
Version
Vue 3.4
Event
- 將新增 todo 部分包進
TodoHeader
component
App.vue
<template>
<TodoHeader @addTodo="onAddTodo" />
</template>
<script setup>
import TodoHeader from '@/components/TodoHeader.vue'
import { addTodo } from '@/api/todos.js'
let onAddTodo = async (val) => {
if (val === '') return
await addTodo(val)
}
</script>
Line 2
<TodoHeader @addTodo="onAddTodo" />
- 使用
TodoHeader
component,此時<input>
與<button>
已經被包在 component 內 TodoHeader
component 會將資料透過addTodo
event 往外拋
Component Naming Convention
Event
:以camelCase
組合兩個單字
Event Handler
:以on
+event名稱
的camelCase
命名
Line 9
let onAddTodo = async (val) => {
if (val === '') return
await addTodo(val)
}
- 在 event handler 內呼叫
addTodo()
API function 新增一筆 todo
TodoHeader
TodoHeader.vue
<template>
<div class="box">
<input type="text" v-model="newTodo" />
<button @click="onAdd">Add</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
let newTodo = ref('')
let emit = defineEmits(['addTodo'])
let onAdd = () => emit('addTodo', newTodo.value)
</script>
<style scoped>
.box {
border-style: solid;
border-width: 2px;
border-color: red;
width: fit-content;
}
</style>
Line 3
<input type="text" v-model="newTodo" />
<button @click="onAdd">Add</button>
- 將
<input>
與<button>
都搬到 component 內
Line 11
let newTodo = ref('')
newTodo
state:儲存新輸入的 todo
Line 12
let emit = defineEmits(['addTodo'])
defineEmits()
:定義 event,其中emit()
為 function
Line 14
let onAdd = () => emit('addTodo', newTodo.value)
- 新增一筆 todo
- 不再此呼叫
addTodo()
API function,因為會把 component 寫死,變得無法在別處使用 - 使用
emit()
觸發addTodo
event,並將資料傳出去
Options API
App.vue
<template>
<TodoHeader @addTodo="onAddTodo" />
</template>
<script>
import TodoHeader from '@/components/TodoHeader.vue'
import { addTodo } from '@/api/todos.js'
export default {
components: {
TodoHeader
},
methods: {
async onAddTodo(val) {
if (val === '') return
await addTodo(val)
}
}
}
</script>
- 最後附上相同功能的 Options API 供參考
- Component 除了要
import
外,還要在components
下宣告
TodoHeader.vue
<template>
<div class="box">
<input type="text" v-model="newTodo" />
<button @click="onAdd">Add</button>
</div>
</template>
<script>
export default {
data: () => ({
newTodo: ''
}),
methods: {
onAdd() {
this.$emit('addTodo', this.newTodo)
}
}
}
</script>
<style scoped>
.box {
border-style: solid;
border-width: 2px;
border-color: red;
width: fit-content;
}
</style>
- 不必宣告 event,直接以
this.$emit()
呼叫即可
Conclusion
- Event 最典型的用法就是將 data 拋出去,由呼叫端負責處理 API 部分,而不會在 Component 內呼叫 API