Vuetify 月份选择器(VDatePicker type="month")完全指南:从基础用法到进阶实战
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
导读
本文聚焦 Vuetify 中v-date-picker组件以type="month"形态运行时的月份选择能力。作为独立的月份选择器界面,它允许用户单独选择月份,或同时选择月份与年份,是构建报表筛选、账期选择、订阅周期管理等场景的高频组件。读完本文,你将掌握月份选择器的两种朝向配置、allowed-months 等核心 prop 的三种传参方式、与v-text-field集成的 Dialog/Menu 组合方案,以及多选、国际化、只读等进阶用法,并了解其底层源码(VDatePicker.tsx、VDatePickerMonths.tsx)是如何支撑这些行为的。
一、月份选择器是什么
在 Vuetify 中,v-date-picker是一个全能型日期选择组件,通过切换type属性可以在三种模式间流转:
type="date"(默认):完整日期(日、月、年)选择;type="month":月份选择,即本文主题;type="year":年份选择。
当设置type="month"时,组件渲染为独立的月份选择器。从源码结构看(VDatePicker.tsx),VDatePicker内部实际上是一个组合式容器:它将 VDatePickerControls(顶部年月导航控件)、VDatePickerHeader(头部标题区)、VDatePickerMonths(12 个月份网格)与 VDatePickerYears(年份列表)按viewMode切换渲染。当用户点击年份控件时,视图会切换到年份列表;点击月份后切回月份网格。月份网格本身由VDatePickerMonths承担,它基于createRange(12)生成 12 个按钮,并通过useGridSelection提供键盘方向键导航与data-v-month网格定位。
注意:本文档对应仓库中的
packages/docs/src/pages/en/components/date-pickers-month.md,在 docs 源码中该页面标记为disabled: true(date-pickers-month.md),但这不影响其示例与组件行为在源码仓库中的可用性,所有示例文件均存在于 v-date-picker-month 目录下。
二、基础用法(Usage)
月份选择器有 portrait(竖版,默认)和 landscape(横版)两种朝向。最简单的用法如下:
<template> <v-row class="justify-center"> <v-date-picker v-model="picker" type="month" ></v-date-picker> </v-row> </template> <script> export default { data () { return { picker: (new Date(Date.now() - (new Date()).getTimezoneOffset() * 60000)).toISOString().substr(0, 10), } }, } </script>对应示例文件:usage.vue。
几点需要说明:
- model 值格式:月份选择器的
v-model接受YYYY-MM形式的月份字符串(如'2017-12'),示例中为了统一演示,初始值用 ISO 字符串截取得到。请以实际业务需要的YYYY-MM字符串为准。 - 默认选中:若不给
v-model赋值,从源码看(VDatePickerMonths.tsx 中的watchEffect),内部会用adapter.getMonth(adapter.date())将模型回填为当前月份。 - 朝向切换:通过
landscapeprop 切换为横版布局,横版下头部会显示在侧边。相关示例见 misc-orientation.vue:
<v-date-picker v-model="picker" :landscape="landscape" type="month" ></v-date-picker>三、核心 Props 详解
月份选择器继承自VDatePicker的整套 props(定义于 VDatePicker.tsx),下面按文档示例逐一展开。
3.1 Allowed months:限定可选月份
allowed-datesprop 可以限制可选择的月份,支持三种传参形式:
- 数组:显式列出允许的日期字符串;
- 对象:以日期为键、布尔值为值的映射;
- 函数:接收日期字符串,返回布尔值,
true表示允许选择。
官方示例(prop-allowed-months.vue)配合min/max使用,函数形式只允许偶数月:
<template> <v-row class="justify-center"> <v-date-picker v-model="date" :allowed-dates="allowedMonths" class="mt-4" max="2019-10" min="2017-06" type="month" ></v-date-picker> </v-row> </template> <script> export default { data () { return { date: '2017-12', } }, methods: { // 只允许选择偶数月份 allowedMonths: val => parseInt(val.split('-')[1], 10) % 2 === 0, }, } </script>提示:
min="2017-06"、max="2019-10"在这里同样接受YYYY-MM格式的月份字符串作为边界。
源码侧佐证:VDatePicker会把allowed-dates解析为allowedMonths计算属性(见 VDatePicker.tsx 与isMonthAllowed实现),数组形式会检查“该月内是否存在任一被允许的日期”,函数形式则遍历该月每一天调用回调;随后传入VDatePickerMonths的allowedMonthsprop,在 VDatePickerMonths.tsx 中逐月计算isDisabled,禁用态月份按钮不可点击。
3.2 Colors:颜色定制
月份选择器的颜色通过color和header-color两个 prop 控制:
color:选中月份(按钮)的主色;header-color:头部标题区颜色;若未提供,头部自动使用color的值。
对应源码逻辑在 VDatePicker.tsx:
const headerColor = toRef(() => props.headerColor ?? props.color)官方示例(prop-colors.vue):
<v-date-picker v-model="picker" color="green-lighten-1" type="month" ></v-date-picker> <v-date-picker v-model="picker2" color="green-lighten-1" header-color="primary" type="month" ></v-date-picker>第一个只设置了color,头部与选中态共用绿色;第二个额外设置header-color="primary",头部独立使用主题 primary 色。
3.3 Icons:图标覆盖
picker 默认使用的导航图标可以通过next-icon、prev-icon、year-icon等 prop 覆盖为任意 Material Design Icons 名称(依赖项目已安装的 mdi 图标集)。官方示例(prop-icons.vue):
<v-date-picker v-model="picker" next-icon="mdi-skip-next" prev-icon="mdi-skip-previous" type="month" year-icon="mdi-calendar-blank" ></v-date-picker>这些图标最终由 VDatePickerControls.tsx 渲染在顶部导航按钮上,分别对应“下一个月/上一个月/切换到年份视图”。
3.4 Multiple:多选月份
通过multipleprop 可以一次选择多个月份,此时v-model必须为数组。官方示例(prop-multiple.vue):
<v-date-picker v-model="months" type="month" multiple ></v-date-picker>months: ['2018-09', '2018-10']源码侧,VDatePicker的useProxiedModel转换逻辑(VDatePicker.tsx)在multiple为真时将模型包裹为数组,写入时若为单值则取v[0]。此外multiple也支持'range'字符串值或数字上限(见 VDatePickerMonth.tsx 的类型定义),当作为数字传入时表示最多可选的月份数量。
3.5 Readonly:只读模式
添加readonlyprop 即可禁止用户选择新日期,适合展示型场景。官方示例(prop-readonly.vue):
<v-date-picker v-model="date" type="month" readonly ></v-date-picker>3.6 Show current:高亮“当前月份”
默认情况下,当前月份会以描边(outlined)按钮形式突出显示。show-currentprop 允许你:
- 设为
false:移除当前月份的高亮边框; - 传一个月份字符串(如
'2013-07'):指定将哪个月份作为“当前”高亮显示。
官方示例(prop-show-current.vue):
<!-- 取消当前月高亮 --> <v-date-picker v-model="month1" :show-current="false" type="month" ></v-date-picker> <!-- 将 2013-07 作为“当前”月份高亮 --> <v-date-picker v-model="month2" show-current="2013-07" type="month" ></v-date-picker>3.7 Width 与 Full-width:宽度控制
使用widthprop 指定固定宽度(支持数字或带单位的字符串,如"290"),使用full-width让 picker 撑满父容器宽度。官方示例(prop-width.vue):
<v-date-picker v-model="date" type="month" width="290" ></v-date-picker> <v-date-picker v-model="date" type="month" full-width ></v-date-picker>四、进阶实战:Dialog 与 Menu 集成
在表单中,月份选择器最常见的用法是挂载到v-text-field上,通过v-menu或v-dialog弹出。官方示例(misc-dialog-and-menu.vue)给出了完整实现,核心要点如下:
- 给
v-text-field添加readonly:避免点击输入框时弹出移动端键盘; - 使用
no-title隐藏 picker 标题:节省垂直空间; - 利用 picker 暴露的 slot 挂钩保存/取消逻辑:
v-menu的save(date)会在确认时把暂存值写回模型;取消则维持旧值不变。
以 Menu 为例:
<v-menu ref="menu" v-model="menuActive" v-model:return-value="date" :close-on-content-click="false" max-width="290px" min-width="auto" transition="scale-transition" > <template v-slot:activator="{ props }"> <v-text-field v-model="date" label="Picker in menu" prepend-icon="mdi-calendar" readonly v-bind="props" ></v-text-field> </template> <v-date-picker v-model="date" type="month" no-title scrollable > <v-spacer></v-spacer> <v-btn color="primary" variant="text" @click="menu = false" > Cancel </v-btn> <v-btn color="primary" variant="text" @click="menu.save(date)" > OK </v-btn> </v-date-picker> </v-menu>Dialog 的写法几乎相同,区别在于:
- 使用
v-dialog包裹,width="290px"且persistent(点击遮罩不自动关闭); - 确定按钮调用
dialog.save(date),取消按钮直接modal = false。
这套模式能实现“确认前不改值、取消即还原”的交互,因为v-menu/v-dialog的return-value绑定会在save()被调用时才提交到date。
五、国际化(Internationalization)
月份选择器通过 JavaScript 原生Date对象支持国际化:使用localeprop 传入 BCP 47 语言标签,月份名称、头部文案、导航文案等都会随之本地化。官方示例(misc-internationalization.vue)演示了泰语(th)与瑞典语(sv-se):
<v-date-picker v-model="picker" locale="th" type="month" ></v-date-picker> <v-date-picker v-model="picker" locale="sv-se" type="month" ></v-date-picker>从源码看,月份按钮的文本与无障碍标签由日期适配器(useDate())的format(date, 'monthShort')/format(date, 'month')生成(见 VDatePickerMonths.tsx),因此月份名完全跟随所设置的 locale。Vuetify 默认使用原生 Intl 能力(date适配器位于 packages/vuetify/src/composables/date),也支持通过date选项替换为 dayjs 等自定义适配器。
六、朝向切换(Orientation)
月份选择器支持两种朝向,默认portrait(竖版),设置landscape后切换为横版,头部信息区移动到左侧、内容区占据剩余宽度。官方示例(misc-orientation.vue)用一个v-checkbox动态切换:
<v-checkbox v-model="landscape" label="Landscape" ></v-checkbox> <v-date-picker v-model="picker" :landscape="landscape" type="month" ></v-date-picker>横版下头部文案的行内换行处理可以在 VDatePicker.tsx 中看到:当格式化后的头部日期为三段式(含星期)时,VDatePicker会用换行符将其拆成两行显示,以适应横版较窄的头部区域。横版头部的宽度还可以通过landscapeHeaderWidthprop 进一步定制。
七、使用注意事项(Caveats)
::: warningv-date-picker接受ISO 8601的日期字符串(YYYY-MM-DD)。关于 ISO 8601 及其它日期标准的更多信息,请参阅国际标准化组织(ISO)发布的官方标准文档。 :::
落实到月份选择器场景,需要特别注意:
- 模型格式:月份选择器的
v-model使用YYYY-MM(如'2018-09'、'2013-07')这种“月份级”字符串,而底层日期适配器解析时仍遵循 ISO 8601 规范(如show-current="2013-07"会被解析为 2013 年 7 月);当与v-text-field、v-menu的return-value组合时,请保持全链路格式一致。 - 时区与截取:官方示例中常用
new Date().toISOString().substr(0, 7)生成当前月份字符串,请注意toISOString()返回的是 UTC 时间,在非 UTC 时区边缘场景可能产生一天偏差;生产代码建议使用YYYY-MM显式构造。 readonly与键盘:将 picker 嵌入v-text-field时务必给输入框加readonly,否则移动端会弹出软键盘干扰操作(见本文第四节)。
八、相关组件与继续探索
月份选择器与以下 Vuetify 组件/文档配合使用效果最佳:
- 日期选择器整体能力:date-pickers;
- 弹出层容器:menus;
- 时间选择器:time-pickers;
- 月份网格源码:VDatePickerMonths.tsx;
- 组合容器源码:VDatePicker.tsx;
- 月份模式测试:VDatePicker.month.spec.ts(含快照 VDatePicker.month.spec.ts.snap),可用来验证月份选择、多选、范围选择等行为。
结语
本文围绕v-date-picker type="month"从基础用法、核心 props(allowed-dates、color/header-color、icons、multiple、readonly、show-current、width/full-width),到 Dialog/Menu 集成、国际化与朝向切换做了完整梳理,并结合 VDatePicker.tsx 与 VDatePickerMonths.tsx 等源码解释了这些能力背后的实现机制。掌握了这些内容,你就可以在报表筛选、账期管理、订阅周期等业务场景中,快速构建出体验完整的月份选择交互。
【免费下载链接】vuetify🐉 Vue Component Framework项目地址: https://gitcode.com/gh_mirrors/vu/vuetify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考