Vuejs自定义日期组件支持v-model

踩坑 v-model。

问题描述

在Vue项目中,使用flatpickr 做一个日期选择器DatePicker的组件,发现使用v-model时出了问题。

上图:

这里当我更新新的日期时,v-model并没有同步更新,而是保持着初始值。

对应的HTML及组件定义的代码如下:

HTML:

<template>
  <div>    
    <div class="form-group row">
      <label class="col-form-label text-right col-4">昵称</label>
      <div class="col">
        <input v-model="nickname" name="nickname" type="text" class="form-control">
      </div>
    </div>
    {{ nickname }}

    <div class="form-group row">
      <label class="col-form-label text-right col-4">生日</label>
      <div class="col">
        <DatePicker v-model="birthday" name="birthday">
      </div>
    </div>
    {{ birthday }}
  </div>
</template>

<script>
  export default {
    data() {
      return {
        nickname: 'lucia',
        birthday: '2018-12-26'  
      }  
    }
  }    
</script>

DatePicker组件的内容:

<template>
  <div class="input-group flatpickr" data-alt-input="true" data-locale="zh" data-alt-format="Y-m-d">
    <input :value="value" :name="name" class="flatpickr-input" data-input="true">
    <a class="input-group-append" data-toggle>
      <span class="input-group-text">
        <i class="far fa-calendar-alt" />
      </span>
    </a>
  </div>
</template>

<script>
import initFlatpickr from './flatpickr'

export default {
  props: [ "value", "name" ],
  mounted() {
    initFlatpickr(this.$el)
  }
}
</script>

「其中initFlatpickr用于创建flatpickr实例,这里它不是重点,具体内容略去。」

Google后,参考Adding v-model Support to Custom Vue.js Components,完美解决。

解决方法

解决问题前,需要了解,v-model 是语法糖,以下两种写法得到的效果是一样的:

<input v-model="message" type="text">

<input :value="message" @input="message = $event.target.value" type="text">

而对于组件DatePicker,我只需要在发生input事件时,将值传给父组件的input事件即可。

接下来就自然而然了。

修改DatePicker组件的input部分内容,监听input事件,当发生input事件后调用updateDate()方法,emit父组件的input事件,将用户选中的值传给父组件。

这里只显示修改部分的代码:

<template>
    ......
  <input :value="value" :name="name" class="flatpickr-input" data-input="true" @input="update" ref="datePicker" @input="updateDate">
    ......
</template>


<script>
  .......
export default {
  .......
  methods: {
    updateDate() {
      this.$emit('input', this.$refs.datePicker.value)
    }
  }
}
</script>

这时再看刚刚的页面,问题解决。

参考

Adding v-model Support to Custom Vue.js Components