You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vuetify2 VDatePicker年份选择器打开位置异常修复咨询

问题解决:Vuetify2 VDatePicker年份视图打开时自动滚动到末尾的问题

问题场景

在Vue2+Vuetify2项目中使用VDatePicker组件,设置active-picker为YEAR,年份范围限定在2000到2100之间。打开组件时,偶尔会自动滚动到末尾年份(如2100、2099),而非停留在当前年份。尝试设置value为new Date()后问题仍存在。

解决方案

核心问题分析

出现该问题的原因主要有两点:

  • VDatePicker同时绑定了v-model="date"和:value="defaultValue",导致值绑定冲突,组件无法正确识别应该定位的年份。
  • 菜单打开时仅切换了active-picker,但未确保date有有效值,当date为空时,组件会默认滚动到年份范围的末尾。

具体修复步骤

  1. 移除重复的value绑定:删除VDatePicker上的:value="defaultValue"属性,仅保留v-model="date"。
  2. 菜单打开时初始化日期:在菜单打开的监听逻辑中,若date为空,将其设置为当前日期的ISO格式字符串,确保年份选择器能定位到当前年份。
  3. 修正日期格式化方法:getFormattedTime方法需返回可读的日期字符串,而非直接返回Date对象。

修改后的代码

组件模板

<v-menu
      v-model="menu"
      :close-on-content-click="false"
      offset-y
      transition="scale-transition"
      min-width="290"
    >
      <template v-slot:activator="{ on, attrs }">
        <div v-if="$slots.activator" v-bind="attrs" v-on="on">
          <slot name="activator"></slot>
        </div>
        <v-card v-else flat width="100%">
          <v-text-field
            :disabled="disabled"
            :outlined="outlined"
            :dense="dense"
            :filled="filled"
            :rules="[...rules]"
            v-bind="attrs"
            v-on="on"
            :value="getFormattedTime(date)"
            :hide-details="hideDetails"
            :label="label"
            placeholder="选择日期"
            :error-messages="errorMessages"
            prepend-inner-icon="mdi-calendar"
            clearable
            @click:clear="clearDate()"
            readonly
          >
            <template v-slot:append>
              <v-icon class="pr-2">
                mdi-menu-down
              </v-icon>
            </template>
          </v-text-field>
        </v-card>
      </template>
      <v-card width="290">
        <v-card-text class="pa-0">
          <v-date-picker
            v-model="date"
            color="primary"
            no-title
            :disabled="disabled"
            :min="min"
            @click:date="changeData"
            :max="max"
            :active-picker.sync="activePicker"
            first-day-of-week="1"
            :readonly="readonly"
          ></v-date-picker>
        </v-card-text>
      </v-card>
    </v-menu>

脚本代码

props: {
    value: {
      required: false,
      type: String
    },
    label: {
      required: false,
      default: "",
      type: String
    },
    min: {
      required: false,
      default: new Date("2000-01-01").toISOString(),
      type: String
    },
    max: {
      required: false,
      default: new Date("2100-01-01").toISOString(),
      type: String
    },
    hideDetails: {
      required: false,
      default: false,
      type: Boolean
    },
    disabled: {
      required: false,
      default: false,
      type: Boolean
    },
    outlined: {
      required: false,
      default: false,
      type: Boolean
    },
    dense: {
      required: false,
      default: false,
      type: Boolean
    },
    filled: {
      required: false,
      default: false,
      type: Boolean
    },
    errorMessages: {
      required: false,
      default: null,
      type: [String, Number, Array, Boolean]
    },
    rules: {
      required: false,
      default: () => [],
      type: Array
    },
    yearSelect: {
      required: false,
      default: true,
      type: Boolean
    },
    readonly: {
      required: false,
      default: false,
      type: Boolean
    }
  },

  data: () => ({
    activePicker: null,
    date: "",
    menu: false
  }),

  watch: {
    value: {
      immediate: true,
      handler() {
        this.date = this.value || "";
      }
    },
    menu(val) {
      if (val) {
        this.$nextTick(() => {
          // 若date为空,设置为当前日期
          if (!this.date) {
            this.date = new Date().toISOString().split('T')[0];
          }
          this.activePicker = 'YEAR';
        });
      }
    }
  },

  methods: {
    changeData() {
      this.$emit("input", this.date);
      this.menu = false;
    },
    close() {
      this.date = "";
      this.changeData();
      this.menu = false;
    },
    toggle() {
      this.menu = !this.menu;
    },
    clearDate() {
      this.date = "";
      this.changeData();
    },
    getFormattedTime(date) {
      if (!date) return "";
      const newDate = new Date(date);
      // 格式化日期为YYYY-MM-DD,可根据需求调整格式
      return `${newDate.getFullYear()}-${String(newDate.getMonth()+1).padStart(2, '0')}-${String(newDate.getDate()).padStart(2, '0')}`;
    }
  }

说明

修改后,每次打开日期选择器时:

  • 若已有选中日期,年份视图会定位到该日期的年份;
  • 若无选中日期,会自动设置当前日期并定位到当前年份,不会再滚动到范围末尾。

内容的提问来源于stack exchange,提问作者WhyMe7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:26:08