點燈坊

失くすものさえない今が強くなるチャンスよ

使用 defineEmits() 定義 Event

Sam Xiao's Avatar 2024-02-21

從 Vue 3 開始,Vue 經過多次語法演進,到目前 Vue 3.2 所提供的 Script Setup 後,Vue 的寫法總算穩定下來,改用 defineEmits() 定義 Event,也是目前 Vue 官網範例的正式寫法,但還是有不少網路上範例或書籍用的是 Vue 3 早期寫法,雖然不再建議這樣寫,但還是得看得懂,並藉此了解 Vue 語法的演變軌跡。

Version

Vue 3.4

Event

<template>
  <MyCounter :initialCount="count" @countChange="onCountChange" />
  {{ count }}
</template>

<script setup>
import { ref } from 'vue'
import MyCounter from '@/components/MyCounter.vue'

let count = ref(0)
let onCountChange = (val) => (count.value = val)
</script>
  • 自行定義 MyConter,將資料傳進 initialCount prop,並接收 component 傳出的 countChange event

Event 類似 function 的回傳值,可將資料透過 event 從 component 傳出

Options API

MyCounter.vue

<template>
  <div class="box">
    <button @click="onClick">Inner +</button>
  </div>
</template>

<script>
export default {
  props: {
    initialCount: Number
  },
  data: function () {
    return {
      count: this.initialCount
    }
  },
  methods: {
    onClick() {
      this.count++
      this.$emit('countChange', this.count)
    }
  }
}
</script>

<style scoped>
.box {
  border-style: solid;
  border-width: 2px;
  border-color: red;
  width: fit-content;
}
</style>
  • Option API 呼叫 event
  • props:在 props key 下定義 prop
  • 使用 this 存取 prop
  • 使用 this.$emit() 發出 event

Composition API

MyCounter.vue

<template>
  <div class="box">
    <button @click="onClick">Inner +</button>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  props: {
    initialCount: Number
  },
  setup(props, { emit }) {
    let count = ref(props.initialCount)

    let onClick = () => {
      count.value++
      emit('countChange', count.value)
    }

    return {
      count,
      onClick
    }
  }
}
</script>

<style scoped>
.box {
  border-style: solid;
  border-width: 2px;
  border-color: red;
  width: fit-content;
}
</style>
  • Vue 3.0 與 3.1 所使用語法
  • Composition API 必須在 setup()組合 後才可使用,並透過 props Object 讀取 prop
  • setup() 第二個參數為 context object,包含 attrsslotsemit、與 expose 四個 property,因為目前只使用到 emit,因此只解構出 emit
  • 使用 emit() 呼叫 event

Script Setup

MyCounter.vue

<template>
  <div class="box">
    <button @click="onClick">Inner +</button>
  </div>
</template>

<script setup>
let props = defineProps({ initialCount: Number })
let emit = defineEmits(['countChange'])

let count = props.initialCount

let onClick = () => {
  count++
  emit('countChange', count)
}
</script>

<style scoped>
.box {
  border-style: solid;
  border-width: 2px;
  border-color: red;
  width: fit-content;
}
</style>
  • 使用 defineEmits() compiler macro 展開,回傳 emit()
  • 使用 emit() 呼叫 event

Conclusion

  • defineEmits() 只是 compiler macro,因此並不需要 import