給定制的vuejs組件添加v-model雙向綁定支持


用過vuejs的前端工程師,對於v-model一定印象深刻。它向類似textarea,input等原生html原生添加雙向數據綁定的能力非常方便。但是對於你的定制vue組件並不是能夠直接應用v-model的,我們需要做一些額外的工作,但是這個額外工作是非常簡單的。

為了理解如何給你的組件提供v-momeiydel支持,你應該深入地了解v-model本身底層是如何工作地。v-model初看起來就像是一個魔術,但是真的沒有那么神秘。

v-model="syncedProp"

等價於以下代碼

:value="syncedProp" @input="syncedProp=$arguments[0] 或者
:value="syncedProp" @input="syncedProp=$event.target.value

理解了以上地兩點,那么如果需要支持v-model,你自己的組件需要做的就是:

1. 接收一個:value的property

2. 當用戶變更value值的時候發送一個@input事件

基礎實現:

我們假設我們有一個date picker的組件,該組件接收year,month的value:{month:1,year:2019},我們希望該組件有兩個輸入Inputs,一個用於month,一個用於year,並且通過v-model來更新綁定的對象.這里是實現的例子代碼:

<template>
  <div class="date-picker">
    Month: <input type="number" ref="monthPicker" :value="value.month" @input="updateDate()"/>
    Year: <input type="number" ref="yearPicker" :value="value.year" @input="updateDate()"/>
  </div>
</template>

<script>
export default {
  props: ['value'],

  methods: {
    updateDate() {
      this.$emit('input', {
        month: +this.$refs.monthPicker.value,
        year: +this.$refs.yearPicker.value
      })
    }
  }
};
</script>

有了以上的實現代碼后,我們就可以像下面的代碼來使用它:

<template>
  <div class="wrapper">
    <date-picker v-model="date"></date-picker>
    <p>
      Month: {{date.month}}
      Year: {{date.year}}
    </p>
  </div>
</template>

<script>
import DatePicker from './DatePicker.vue';

export default {
  components: {
    DatePicker
  },

  data() {
    return {
      date: {
        month: 1,
        year: 2017
      }
    }
  }
})
</script>

總結以上范例代碼,我們可以看到就做了兩件事:

1. 接受一個value這個prop,並通過該value prop傳入的值在本組件中使用

2. 當需要通知外部數據已經變化需要更新外部的綁定數據時,只需要emit一個input事件即可!

高級一點的例子

在上面基礎版本基礎上,我們把事情搞得稍微復雜一點,比如,我們傳入的日期格式不是object形式,而時字符串形式mm/yyyy的格式,這時需要使用的化,必須要做進一步處理,同樣地,當用戶主動修改了數據修正外部地數據時,也需要再組合成一個字符串emit出去!

<template>
  <div class="date-picker">
    Month: <input type="number" ref="monthPicker" :value="splitDate.month" @input="updateDate()"/>
    Year: <input type="number" ref="yearPicker" :value="splitDate.year" @input="updateDate()"/>
  </div>
</template>

<script>
export default {
  props: ['value'],

  computed: {
    splitDate() {
      const splitValueString = this.value.split('/');

       return {
        month: splitValueString[0],
        year: splitValueString[1]
      }
    }
  },

  methods: {
    updateDate() {
      const monthValue = this.$refs.monthPicker.value;
      const yearValue = this.$refs.yearPicker.value;
      this.$emit('input', `${monthValue}/${yearValue}`);
    }
  }
};
</script>

定制v-model所使用的prop和event

如上面所說,v-model匹配的就是value屬性以及input的事件上報,但是我們也可以修改這個默認的行為。

其辦法就是通過在我們的定制組件中,聲明一個model對象,該model對象包含兩個字段,一個prop,一個event分別用於對應的value和input事件

比如下面的組件代碼:

export default {
  prop: ['cprop'],
  model: {
      prop: 'cprop',
      event: 'cevent'
  }
  methods: {
      handleInput (value) {
          this.$emit('cevent', value)
      }
  }
}

如果我們在html中像下面來使用:

<basic-input v-model="email" />
<!-- 等價於以下代碼 -->
<basic-input :cprop="email" @cevent="e => email = e.target.value" />

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM