Vuetify 中的自定义日期选择器

Bil*_*adj 1 javascript vue.js nuxt.js vuetify.js

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

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

在此处输入图片说明

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

[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
Run Code Online (Sandbox Code Playgroud)

父组件是 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>
Run Code Online (Sandbox Code Playgroud)

子组件是 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>
Run Code Online (Sandbox Code Playgroud)

如何克服我的问题?

如果您有时间,可以在 Github 上找到这个简单的演示:)

更新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>
Run Code Online (Sandbox Code Playgroud)

Dji*_*jip 5

我为使其正常工作所做的更改是,我添加了computed一个get()set()。getter 将返回当前选定的值,setter 将在每次更改时发出新值。

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

自定义日期选择器.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>
Run Code Online (Sandbox Code Playgroud)