跳轉到內容

元件事件

本頁面假設您已經閱讀了元件基礎知識。如果您是元件的新手,請先閱讀。

發出和監聽事件

元件可以直接在模板表示式(例如,在v-on處理器中)中使用內建的$emit方法發出自定義事件

模板
<!-- MyComponent -->
<button @click="$emit('someEvent')">Click Me</button>

$emit()方法也作為this.$emit()在元件例項上可用

js
export default {
  methods: {
    submit() {
      this.$emit('someEvent')
    }
  }
}

父元件可以使用v-on監聽它

模板
<MyComponent @some-event="callback" />

元件事件監聽器也支援.once修飾符

模板
<MyComponent @some-event.once="callback" />

與元件和props一樣,事件名稱提供自動的大小寫轉換。注意我們發出的是camelCase事件,但可以在父元件中使用kebab-cased監聽器來監聽它。與props的大小寫一樣,我們建議在模板中使用kebab-cased事件監聽器。

提示

與原生DOM事件不同,元件發出的事件不會冒泡。您只能監聽直接子元件發出的事件。如果需要在不同兄弟元件或深層巢狀元件之間進行通訊,請使用外部事件匯流排或全域性狀態管理解決方案

事件引數

有時,在事件中發出特定值很有用。例如,我們可能希望<BlogPost>元件負責調整文字的大小。在這些情況下,我們可以向$emit傳遞額外的引數以提供此值

模板
<button @click="$emit('increaseBy', 1)">
  Increase by 1
</button>

然後,當我們監聽父元件中的事件時,我們可以使用內聯箭頭函式作為監聽器,這允許我們訪問事件引數

模板
<MyButton @increase-by="(n) => count += n" />

或者,如果事件處理器是一個方法

模板
<MyButton @increase-by="increaseCount" />

那麼值將作為該方法的第一個引數傳遞

js
methods: {
  increaseCount(n) {
    this.count += n
  }
}
js
function increaseCount(n) {
  count.value += n
}

提示

所有傳遞給$emit()的額外引數(在事件名稱之後)都將轉發給監聽器。例如,使用$emit('foo', 1, 2, 3)時,監聽函式將接收到三個引數。

宣告事件

元件可以使用defineEmits()宏(defineEmits())顯式宣告它將發出的事件emits選項

vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>

我們在<template>中使用的$emit方法在元件的<script setup>部分中不可用,但defineEmits()返回一個等效函式,我們可以用它來代替。

vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])

function buttonClick() {
  emit('submit')
}
</script>

defineEmits()不能在函式中使用,它必須直接放在上面的示例中<script setup>內。

如果你使用的是顯式的setup函式而不是<script setup>,則應使用emits選項來宣告事件,並且emit函式將在setup()上下文中暴露。

js
export default {
  emits: ['inFocus', 'submit'],
  setup(props, ctx) {
    ctx.emit('submit')
  }
}

setup()上下文的其他屬性一樣,emit可以安全地進行解構。

js
export default {
  emits: ['inFocus', 'submit'],
  setup(props, { emit }) {
    emit('submit')
  }
}
js
export default {
  emits: ['inFocus', 'submit']
}

emits選項和defineEmits()宏也支援物件語法。如果你使用TypeScript,你可以對引數進行型別註解,這使得我們可以在執行時驗證發出事件的負載。

vue
<script setup lang="ts">
const emit = defineEmits({
  submit(payload: { email: string, password: string }) {
    // return `true` or `false` to indicate
    // validation pass / fail
  }
})
</script>

如果你使用TypeScript與<script setup>一起使用,也可以使用純型別註解來聲明發出的事件。

vue
<script setup lang="ts">
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()
</script>

更多資訊:元件發出事件的型別註解

js
export default {
  emits: {
    submit(payload: { email: string, password: string }) {
      // return `true` or `false` to indicate
      // validation pass / fail
    }
  }
}

另請參閱:元件發出事件的型別註解

雖然這不是必需的,但建議定義所有發出的事件,以便更好地記錄元件應該如何工作。這也允許Vue排除已知的監聽器從穿透屬性,避免由第三方程式碼手動派發的DOM事件引起的邊緣情況。

提示

如果將原生事件(例如,click)定義在emits選項中,監聽器現在將僅監聽元件發出的click事件,而不再響應原生click事件。

事件驗證

與屬性型別驗證類似,如果使用物件語法而不是陣列語法定義,則可以驗證發出的事件。

要新增驗證,將事件分配給一個函式,該函式接收傳遞給this.$emitemit呼叫的引數,並返回一個布林值以指示事件是否有效。

vue
<script setup>
const emit = defineEmits({
  // No validation
  click: null,

  // Validate submit event
  submit: ({ email, password }) => {
    if (email && password) {
      return true
    } else {
      console.warn('Invalid submit event payload!')
      return false
    }
  }
})

function submitForm(email, password) {
  emit('submit', { email, password })
}
</script>
js
export default {
  emits: {
    // No validation
    click: null,

    // Validate submit event
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
}
元件事件已載入