Vue 3.0 自定義事件

2021-07-16 11:29 更新

該頁(yè)面假設(shè)你已經(jīng)閱讀過(guò)了組件基礎(chǔ)。如果你還對(duì)組件不太了解,推薦你先閱讀它。

#事件名

不同于組件和 prop,事件名不存在任何自動(dòng)化的大小寫(xiě)轉(zhuǎn)換。而是觸發(fā)的事件名需要完全匹配監(jiān)聽(tīng)這個(gè)事件所用的名稱(chēng)。舉個(gè)例子,如果觸發(fā)一個(gè) camelCase 名字的事件:

  1. this.$emit('myEvent')

則監(jiān)聽(tīng)這個(gè)名字的 kebab-case 版本是不會(huì)有任何效果的:

  1. <!-- 沒(méi)有效果 -->
  2. <my-component @my-event="doSomething"></my-component>

不同于組件和 prop,事件名不會(huì)被用作一個(gè) JavaScript 變量名或 property 名,所以就沒(méi)有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件監(jiān)聽(tīng)器在 DOM 模板中會(huì)被自動(dòng)轉(zhuǎn)換為全小寫(xiě) (因?yàn)?HTML 是大小寫(xiě)不敏感的),所以 @myEvent 將會(huì)變成 @myevent——導(dǎo)致 myEvent 不可能被監(jiān)聽(tīng)到。

因此,我們推薦你始終使用 kebab-case 的事件名。

#定義自定義事件

在 Vue School 上觀看關(guān)于定義自定義事件的免費(fèi)視頻。

可以通過(guò) emits 選項(xiàng)在組件上定義已發(fā)出的事件。

  1. app.component('custom-form', {
  2. emits: ['in-focus', 'submit']
  3. })

當(dāng)在 emits 選項(xiàng)中定義了原生事件 (如 click) 時(shí),將使用組件中的事件替代原生事件偵聽(tīng)器。

TIP

建議定義所有發(fā)出的事件,以便更好地記錄組件應(yīng)該如何工作。

#驗(yàn)證拋出的事件

與 prop 類(lèi)型驗(yàn)證類(lèi)似,如果使用對(duì)象語(yǔ)法而不是數(shù)組語(yǔ)法定義發(fā)出的事件,則可以驗(yàn)證它。

要添加驗(yàn)證,將為事件分配一個(gè)函數(shù),該函數(shù)接收傳遞給 $emit 調(diào)用的參數(shù),并返回一個(gè)布爾值以指示事件是否有效。

  1. app.component('custom-form', {
  2. emits: {
  3. // 沒(méi)有驗(yàn)證
  4. click: null,
  5. // 驗(yàn)證submit 事件
  6. submit: ({ email, password }) => {
  7. if (email && password) {
  8. return true
  9. } else {
  10. console.warn('Invalid submit event payload!')
  11. return false
  12. }
  13. }
  14. },
  15. methods: {
  16. submitForm() {
  17. this.$emit('submit', { email, password })
  18. }
  19. }
  20. })

#v-model 參數(shù)

默認(rèn)情況下,組件上的 v-model 使用 modelValue 作為 prop 和 update:modelValue 作為事件。我們可以通過(guò)向 v-model 傳遞參數(shù)來(lái)修改這些名稱(chēng):

  1. <my-component v-model:foo="bar"></my-component>

在本例中,子組件將需要一個(gè) foo prop 并發(fā)出 update:foo 要同步的事件:

  1. const app = Vue.createApp({})
  2. app.component('my-component', {
  3. props: {
  4. foo: String
  5. },
  6. template: `
  7. <input
  8. type="text"
  9. :value="foo"
  10. @input="$emit('update:foo', $event.target.value)">
  11. `
  12. })

  1. <my-component v-model:foo="bar"></my-component>

#多個(gè) v-model 綁定

通過(guò)利用以特定 prop 和事件為目標(biāo)的能力,正如我們之前在 v-model 參數(shù)中所學(xué)的那樣,我們現(xiàn)在可以在單個(gè)組件實(shí)例上創(chuàng)建多個(gè) v-model 綁定。

每個(gè) v-model 將同步到不同的 prop,而不需要在組件中添加額外的選項(xiàng):

  1. <user-name
  2. v-model:first-name="firstName"
  3. v-model:last-name="lastName"
  4. ></user-name>

  1. const app = Vue.createApp({})
  2. app.component('user-name', {
  3. props: {
  4. firstName: String,
  5. lastName: String
  6. },
  7. template: `
  8. <input
  9. type="text"
  10. :value="firstName"
  11. @input="$emit('update:firstName', $event.target.value)">
  12. <input
  13. type="text"
  14. :value="lastName"
  15. @input="$emit('update:lastName', $event.target.value)">
  16. `
  17. })

點(diǎn)擊此處實(shí)現(xiàn)

#處理 v-model 修飾符

在 2.x 中,我們對(duì)組件 v-model 上的 .trim 等修飾符提供了硬編碼支持。但是,如果組件可以支持自定義修飾符,則會(huì)更有用。在 3.x 中,添加到組件 v-model 的修飾符將通過(guò) modelModifiers prop 提供給組件:

當(dāng)我們學(xué)習(xí)表單輸入綁定時(shí),我們看到 v-model內(nèi)置修飾符——.trim、.number.lazy。但是,在某些情況下,你可能還需要添加自己的自定義修飾符。

讓我們創(chuàng)建一個(gè)示例自定義修飾符 capitalize,它將 v-model 綁定提供的字符串的第一個(gè)字母大寫(xiě)。

添加到組件 v-model 的修飾符將通過(guò) modelModifiers prop 提供給組件。在下面的示例中,我們創(chuàng)建了一個(gè)組件,其中包含默認(rèn)為空對(duì)象的 modelModifiers prop。

請(qǐng)注意,當(dāng)組件的 created 生命周期鉤子觸發(fā)時(shí),modelModifiers prop 包含 capitalize,其值為 true——因?yàn)樗辉O(shè)置在 v-model 綁定 v-model.capitalize="bar"。

  1. <my-component v-model.capitalize="bar"></my-component>

  1. app.component('my-component', {
  2. props: {
  3. modelValue: String,
  4. modelModifiers: {
  5. default: () => ({})
  6. }
  7. },
  8. template: `
  9. <input type="text"
  10. :value="modelValue"
  11. @input="$emit('update:modelValue', $event.target.value)">
  12. `,
  13. created() {
  14. console.log(this.modelModifiers) // { capitalize: true }
  15. }
  16. })

現(xiàn)在我們已經(jīng)設(shè)置了 prop,我們可以檢查 modelModifiers 對(duì)象鍵并編寫(xiě)一個(gè)處理器來(lái)更改發(fā)出的值。在下面的代碼中,每當(dāng) <input/> 元素觸發(fā) input 事件時(shí),我們都將字符串大寫(xiě)。

  1. <div id="app">
  2. <my-component v-model.capitalize="myText"></my-component>
  3. {{ myText }}
  4. </div>

  1. const app = Vue.createApp({
  2. data() {
  3. return {
  4. myText: ''
  5. }
  6. }
  7. })
  8. app.component('my-component', {
  9. props: {
  10. modelValue: String,
  11. modelModifiers: {
  12. default: () => ({})
  13. }
  14. },
  15. methods: {
  16. emitValue(e) {
  17. let value = e.target.value
  18. if (this.modelModifiers.capitalize) {
  19. value = value.charAt(0).toUpperCase() + value.slice(1)
  20. }
  21. this.$emit('update:modelValue', value)
  22. }
  23. },
  24. template: `<input
  25. type="text"
  26. :value="modelValue"
  27. @input="emitValue">`
  28. })
  29. app.mount('#app')

對(duì)于帶參數(shù)的 v-model 綁定,生成的 prop 名稱(chēng)將為 arg + "Modifiers"

  1. <my-component v-model:foo.capitalize="bar"></my-component>

  1. app.component('my-component', {
  2. props: ['foo', 'fooModifiers'],
  3. template: `
  4. <input type="text"
  5. :value="foo"
  6. @input="$emit('update:foo', $event.target.value)">
  7. `,
  8. created() {
  9. console.log(this.fooModifiers) // { capitalize: true }
  10. }
  11. })
以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)