Vue-101-Day 15

|

自定義事件

事件名稱(Event name)不會提供任何大小寫自動轉換的機制,再DOM 使用 v-on 監聽事件會自動轉換成小寫,所以v-on:myEvent會變成v-on:myevent,導致 myEvent 監聽不到

使用 kebab-case

Vue 官方推薦使用 kebab-case 當作使用事件名稱的命名方式

客製化 Component 使用 v-model

預設 Component 會使用value 當作 propinput 當作 event,但有時會利用不同的值,做不同的事情,像是在 input type = checkbox or radio button 的時候

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
  <input
    type="checkbox"
    v-bind:checked="checked"
    v-on:change="$emit('change',$event.target.checked)"
  >`
})
new Vue({
  el: '#app-22',
  data: {
    lovingVue: true
  }
})
<div id="app-22">
  <base-checkbox v-model="lovingVue"></base-checkbox>
</div>

上述的v-model="lovingVue"會將值傳入名為 checked 的 prop,當 base-checkbox 觸發 change 事件時並附帶新的 value,lovingVue 這個屬性將會被更新

註:於 Vue2.2 以上使用

在 component 綁定原生事件

若要在 component 監聽原生事件,可以使用v-on 的 .native 修飾符

Vue.component('base-input', {
  template: `
  <input
    type="text"
    v-bind:value="lovingVue"
  >`
})

new Vue({
  el: '#app-22',
  data: {
    lovingVue: 'Vue is great!'
  },
  methods: {
    onFocus: function(el) {
      console.log(el) // FocusEvent{...}
    }
  }
})
<div id="app-22">
  <base-input v-bind:value="lovingVue" v-on:focus.native="onFocus">
  </base-input>
</div>

將上述 base-input 做調整,根元素調整為 label 而不是 input,如下

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  template: `
  <label>
    {{ label }}
    <input
      v-bind="$attrs"
      v-bind:value="value"
    >
  </label>`
})

new Vue({
  el: '#app-22',
  data: {
    lovingVue: 'I love vue very much',
    msg: 'Hi everyone'
  },
  methods: {
    onFocus: function(el) {
      console.log(el) // FocusEvent{...}
    }
  }
})

會發現v-on:focus.native="onFocus" 事件似乎會失敗,因為 focus.native 是綁定到根元素(label)導致 focus 事件沒有被觸發

若要正確的執行事件,需使用 Vue 提供的v-on="listeners"綁定組件事件

依上述範例

  • 加入 inputListeners
  • 將父組件 focus 移除 native 修飾符
Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function() {
      var vm = this
      return Object.assign({}, this.$listeners, {
        input: function(event) {
          vm.$emit('input', event.target.value)
        }
      })
    }
  },
  template: `
  <label>
    {{ label }}
    <input
      v-bind="$attrs"
      v-bind:value="value"
      v-on="$listeners"
    >
  </label>`
})
<div id="app-22">
  <base-input :label="lovingVue" :value="msg" v-on:focus="onFocus">
  </base-input>
</div>

即可正常執行 focus 事件

.sync 修飾符

在某些情況下,prop 也需要執行雙向綁定,官方推薦以update:myPropName的模式觸發事件

Vue.component('base-button', {
  props: ['title'],
  template: `
    <button @click="click">{{title}}</button>
  `,
  methods: {
    click() {
      // 反轉button中的字串
      const newTitle = this.title
        .split('')
        .reverse()
        .join('')
      this.$emit('update:title', newTitle)
    }
  }
})

new Vue({
  el: '#app-23',
  data: {
    title: 'I Love Vue.js'
  }
})

父組件可以監聽該事件,並更新 title 字串

<div id="app-23">
  <base-button :title="title" @update:title="title=$event"></base-button>
</div>

為了方便撰寫,Vue 也提供較簡易的寫法,與上述的寫法效果是同樣的

<base-button :title.sync="title"></base-button>

參考資料:

Comments