【问题标题】:Custom date picker in VuetifyVuetify 中的自定义日期选择器
【发布时间】:2020-04-11 17:45:49
【问题描述】:

我需要在不同的组件中使用 Vuetify v-date-picker。但这会导致代码重复。所以我认为创建一个自定义的<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

父组件是 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>

如何解决我的问题?

如果你有时间的话,这个simple demo 可以在 Github 上找到:)

更新 1:

我通过避免改变 prop value 成功摆脱了上面的错误消息。我可以选择日期,当我点击 Ok 按钮时,我会正确记录日期控制台。

问题是父组件的文本字段没有显示我选择的日期,它保持如上图所示。

下面是子组件的更新代码:

<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>

【问题讨论】:

  • 如何克服我的问题 ...我建议你避免直接改变道具相反,使用数据或基于道具值的计算属性
  • 谢谢,这正是我现在避免的(在我发布问题之后),当我按下按钮时,我得到了选择的日期,但它暂时没有反映在文本字段中(它保持在图片上)@JaromandaX
  • 你发布了新代码@JaromandaX 吗?
  • 我用相关代码和解释更新了我的帖子。 @Djip
  • 我用一半工作代码@JaromandaX 更新了我的问题

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


【解决方案1】:

我为使其正常工作所做的更改是添加了computedget()set()。 getter 将返回当前选定的值,而 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>

【讨论】:

  • 不客气,如果一切似乎“稍后”正常,请记住将答案标记为正确:)
  • 这是一种非常干净的方法。
  • 几个月后,我必须再次感谢您,因为在类似情况下我仍然使用您的解决方案作为自己的参考:) –
猜你喜欢
  • 2020-02-05
  • 2021-09-24
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多