Vuetify中的自定义日期选择器

时间:2019-12-19 06:42:53

标签: javascript vue.js vuetify.js nuxt.js

我需要在不同的组件中使用Vuetify v-date-picker。但这将导致代码重复。因此,我认为创建一个自定义<custom-date-picker />组件可以在任何需要的地方使用会很有趣。

  • 此子级组件应向父级发送格式化日期的值。
  • 父组件具有一个按钮,该按钮可控制台记录格式化日期

enter image description here

但是使用我当前的代码,我收到以下错误消息:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

found in

---> <CustomDatePicker> at components/CustomDatePicker.vue
       <Pages/index.vue> at pages/index.vue

父组件是pages / index.vue

<template>
  <div>
    <custom-date-picker v-model="date" />
    <v-btn @click="getDate">
      Ok
    </v-btn>
  </div>
</template>

<script>
import CustomDatePicker from '@/components/CustomDatePicker.vue'

export default {
  components: { CustomDatePicker },
  data () {
    return {
      date: ''
    }
  },
  methods: {
    getDate () {
      console.log(this.date)
    }
  }
}
</script>

子组件是components / CustomDatePicker.vue

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-bind:value="value"
              v-on:input="$emit('input', $event)"
              @blur="date = parseDate(value)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-model="date"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null
    }
  },

  computed: {
    computedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.value = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>

如何解决我的问题?

如果有时间,可以在Github上使用此simple demo:)

更新1:

通过避免对prop value进行变异,我成功摆脱了上面的错误消息。我可以选择日期,然后单击确定按钮,可以正确记录日期控制台。

问题在于父组件的文本字段未显示我选择的日期,而是保留了上图中显示的日期。

这是子组件的更新代码:

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-model="dateFormatted"
              @blur="date = parseDate(dateFormatted)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-bind:value="value"
            v-on:input="$emit('input', $event)"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'CustomDatePicker',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      menu1: null,
      date: null,
      dateFormatted: null
    }
  },

  computed: {
    computedDateFormatted () {
      return this.formatDate(this.date)
    }
  },

  watch: {
    date (val) {
      this.dateFormatted = this.formatDate(this.date)
    }
  },
  methods: {
    formatDate (date) {
      if (!date) { return null }
      return date
    },
    parseDate (date) {
      if (!date) { return null }

      const [year, month, day] = date.split('-')
      return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
    }
  }
}
</script>

1 个答案:

答案 0 :(得分:1)

为了使它起作用而进行的更改是,我添加了computedget()set()。吸气剂将返回当前选择的值,而每次更改时,setter都会发出新值。

这是在自定义组件中利用v-model的好方法。

CustomDatePicker.vue

<template>
  <v-container fill-height>
    <v-row justify="center" align="center">
      <v-col cols="12">
        <!-- Date picker -->
        <v-menu
          ref="menu1"
          v-model="menu1"
          :close-on-content-click="false"
          transition="scale-transition"
          offset-y
        >
          <template v-slot:activator="{ on }">
            <v-text-field
              v-model="selected"
              v-on:input="$emit('input', $event)"
              @blur="date = parseDate(value)"
              v-on="on"
              value
              label="Date"
              color="green lighten-1"
            />
          </template>
          <v-date-picker
            v-model="selected"
            @input="menu1 = false"
            no-title
            header-color="green lighten-1"
            color="green lighten-1"
          />
        </v-menu>
        <!-- end of date picker -->
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
  export default {
    name: 'CustomDatePicker',
    props: {
      value: {
        type: String,
        default: ''
      }
    },
    data () {
      return {
        menu1: null,
        date: null
      }
    },

    computed: {
      selected: {
        get() {
          return this.value
        },
        set(value) {
          this.$emit('input', value)
        }
      },
      computedDateFormatted () {
        return this.formatDate(this.date)
      }
    },

    watch: {
      date (val) {
        this.value = this.formatDate(this.date)
      }
    },
    methods: {
      formatDate (date) {
        if (!date) { return null }
        return date
      },
      parseDate (date) {
        if (!date) { return null }

        const [year, month, day] = date.split('-')
        return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
      }
    }
  }
</script>