ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

v-calendar 的 v-date-picker 完全指南:单日期、范围、日期时间选择与表单集成实战

v-calendar 的 v-date-picker 完全指南:单日期、范围、日期时间选择与表单集成实战 前端UI组件【免费下载链接】v-calendarAn elegant calendar and datepicker plugin for Vue.项目地址https://gitcode.com/gh_mirrors/vc/v-calendar点击查看免费下载v-date-picker是 v-calendar 插件内置的功能完备的日期选择器组件本质上是对v-calendar的封装开箱即用地继承后者全部 props 与事件并额外提供日期范围、日期时间、时间三种选择模式以及可直接绑定字符串/时间戳数据的model-config机制。阅读本文后你将掌握如何在 Vue 项目中用v-date-picker实现单日期、日期范围、日期时间、纯时间选择完成自定义输入弹层、禁用日期、必填约束与选中态样式定制并理解其背后的源码级取值与校验流水线。版本提示v2.0.0引入了大量破坏性变更升级前请阅读 升级指南。一、组件定位与安装在 package.json 中可确认插件包名为v-calendar通过 npm 安装即可npm i --save v-calendar安装后在入口处注册插件组件前缀默认为v见 src/utils/defaults/index.js 中的componentPrefix: v即可全局使用v-date-picker与v-calendar。v-date-picker的封装关系体现在 src/components/DatePicker.vue 的渲染函数中它内部渲染一个Calendar组件作为核心日历面板再将日期选择逻辑、输入框格式化/解析、Popover 弹层管理叠加其上。因此官方文档明确指出开箱即用它接受v-calendar的所有 props 并派发所有相同事件。其全部自有 props 定义可参考 docs/api/v2.0/datepicker.md 的 Props 章节。二、单日期与日期范围最基本的 v-model 绑定2.1 单日期选择最基础的用法是使用v-model绑定一个Date对象v-date-picker v-modeldate /data() { return { date: new Date(), } }组件内部将value归一化为标准日期DatePicker.vue的created()钩子中调用normalizeValue并在用户选择后通过input事件回写从而实现双向绑定。2.2 日期范围选择设置is-rangeprop 后v-model绑定一个包含start/end的对象v-date-picker v-modelrange is-range /data() { return { range: { start: new Date(2020, 0, 1), end: new Date(2020, 0, 5) } } }范围模式下组件会启用拖拽选择交互点击起始日并拖动鼠标到结束日即可一次性选中范围。从源码看is-range状态下DatePicker.vue的refreshDateParts()会为start/end分别维护一份日期部件date parts内部通过RANGE_PRIORITYNONE/START/END/BOTH见 DatePicker.vue来控制范围排序时优先保留哪一端。三、三种选择模式date、dateTime 与 timemodeprop 用于切换三种日期与时间选择模式。源码中对应MODE常量见 DatePicker.vuedate、datetime、time由于判断时使用mode.toLowerCase()文档中的dateTime与源码中的datetime均可识别。⚠️ v2.0 破坏性变更旧版本中mode用于切换date/range/multiple三种选择方式。v2.0 起mode仅负责日期与时间维度范围改用is-rangeprop 开启旧的multiple多选行为可通过v-calendar原生的attributesprop dayclick事件重新实现参考 docs/examples/datepickers.md 中的 Legacy Multiple Mode 示例。3.1 mode: date默认限制用户只能选择日期部分月、日、年。由于这是默认值可不显式声明v-date-picker modedate v-modeldate /3.2 mode: dateTime日期 时间允许同时选择日期与时间日历下方会出现一个时间选择器对应 src/components/TimePicker.vuediv div classflex mb-2 label classtext-gray-600 font-mediuminput classmr-1 typeradio value v-modeltimezoneLocal/label label classtext-gray-600 font-medium ml-3input classmr-1 typeradio valueutc v-modeltimezoneUTC/label /div v-date-picker v-modeldate modedateTime :timezonetimezone / /divdata() { return { date: new Date(), timezone: , } } 时间分量使用timezoneprop 指定的时区来设定。默认值为null即使用浏览器本地时区。当timezone变化时组件会重新计算日期部件并重排输入值见 DatePicker.vue 的timezonewatcher。24 小时制is24hris24hrprop 用于将小时下拉框和默认输入格式切换为 24 小时制默认false即 12 小时制v-date-picker v-modeldate modedateTime is24hr template v-slot{ inputValue, inputEvents } input classpx-2 py-1 border rounded focus:outline-none focus:border-blue-300 :valueinputValue v-oninputEvents / /template /v-date-picker在 TimePicker.vue 中可以看到非 24 小时制时会在时分选择器右侧渲染 AM/PM 按钮组并在计算属性中按上午/下午分别过滤小时选项。合法小时valid-hoursvalid-hoursprop 用于限定可选小时接受三种形态数组显式列出合法小时值v-date-picker v-modeldate :valid-hours[0,3,4,5,8,16,20] is24hr /对象min/max指定区间v-date-picker v-modeldate :valid-hours{ min: 4, max: 17 } is24hr /函数接收(hour, dateParts)返回布尔值例如仅周末允许 8-12 点v-date-picker v-modeldate :valid-hours(hour, { weekday }) ![1, 7].includes(weekday) || (hour 8 hour 12) /其底层实现在 src/utils/locale.jshourIsValid()分别处理数组includes判断、对象min hour max与函数三种情况再由getHourOptions()从 0-23 的完整选项列表中过滤出合法小时。valid-hours在 24 小时制下表现最佳但同样兼容 12 小时制——此时 AM/PM 按钮会根据当前时段的合法小时自动禁用。分钟步进minute-incrementminute-incrementprop 设置分钟下拉框的间隔例如每 5 分钟一项v-date-picker v-modeldate modedateTime :minute-increment5 /export default { data() { let date new Date(); date.setMinutes(0, 0, 0); return { date, }; }, };对应实现是 locale.js 的getMinuteOptions()从 0 到 59 按步进值生成选项minuteIncrement小于等于 0 时回退为 1。⚠️ 版本行为差异在v2.4.0之前若绑定日期的时间不是minute-increment选项之一会如实显示该分钟值但该选项处于禁用态v2.4.0起时间会被就近取整到可用的分钟和小时见 locale.js 的nearestOptionValue()它会在选项中寻找与当前值差值最小的可用项。3.3 mode: time纯时间限制用户只选择时间分量时、分、秒不显示日历网格div div classflex mb-2 v-ifmode ! date label classtext-gray-600 font-mediuminput classmr-1 typeradio value v-modeltimezoneLocal/label label classtext-gray-600 font-medium ml-3input classmr-1 typeradio valueutc v-modeltimezoneUTC/label /div v-date-picker modetime v-modeldate :timezonetimezone / div classflex items-baseline mt-2 span classtext-gray-600 font-semibold tracking-wideDate (ISO):/span span classtext-gray-800 ml-2{{ date.toISOString() }}/span /div /divexport default { data() { return { date: new Date(), timezone: , }; }, }从 DatePicker.vue 的渲染逻辑可以看出time模式下不再渲染Calendar而是直接在一个vc-container容器内渲染时间选择器TimePicker。由于时间本身不包含日期信息mode: time通常配合model-config的fillDate使用详见下文用某个基准日期补全缺失的年月日。四、Model Config无痛对接业务数据格式model-configprop 用于描述绑定到v-date-picker的数据形态。比如日期在数据库中存为字符串或时间戳时可以直接绑定该原始值无需在应用里做任何转换。一句话概括model-config与timezone两个 prop 共同提供了零转换的数据对接方案。源码中 DatePicker.vue 定义了基础配置const _baseConfig { type: auto, // 自动识别类型date / string / number / object mask: iso, // type 为 string 时使用的格式化掩码 timeAdjust: , // HH:MM:SS 或 now };4.1 绑定字符串type: string提供model-config并指定type: string与mask即可直接绑定后端返回的日期字符串v-date-picker v-modelcustomer.birthday :model-configmodelConfig is-required /export default { data() { return { customer: { name: Nathan Reyes, birthday: 1983-01-21, }, modelConfig: { type: string, mask: YYYY-MM-DD, // 缺省时使用 iso }, } } };4.2 绑定数字type: numbertype: number对应毫秒时间戳自 1970-01-01 起的毫秒数v-date-picker v-modelcustomer.birthday :model-configmodelConfig /export default { data() { return { customer: { name: Nathan Reyes, birthday: 411976800000, // Milliseconds since 1 January 1970 }, modelConfig: { type: number, }, } } };4.3 时间调整timeAdjust默认情况下用户选择新日期时组件会保留原有的时间值。若希望在选日期时自动调整时间可在model-config中通过timeAdjust指定格式为HH:mm:ss所有时间使用timezone指定缺省为本地时区。v-date-picker v-modeldate :model-configmodelConfigdata() { return { customer: { name: Nathan Reyes, birthday: 1983-01-21T07:30:00.000Z, }, modelConfig: { type: string, mask: iso, timeAdjust: 12:00:00, // 将所选日期的时间调整为当地正午 }, } }timeAdjust支持两种取值Time SettingDescriptionHH:mm:ss自定义时间格式为HH:mm:ssnow赋值为用户选择该日期的当下时刻其实现位于 locale.js 的adjustTimeForDate()timeAdjust now时取当前时刻的时分秒毫秒否则将字符串按2000-01-01T${timeAdjust}Z解析后取 UTC 时分秒紧接着还会用validHours/minuteIncrement就近取整小时与分钟。为日期范围分别调整时间与日期范围搭配时modelConfig可写成含start/end两个属性的对象。例如希望用户选择范围后范围起始于首日 00:00:00、结束于末日 23:59:59v-date-picker v-modelrange :model-configmodelConfig is-range data() { return { range: { start: new Date(2020, 0, 6), end: new Date(2020, 0, 9), }, modelConfig: { start: { timeAdjust: 00:00:00, }, end: { timeAdjust: 23:59:59, }, }, } }源码中normalizeConfig()见 DatePicker.vue会把传入的modelConfig归一化为长度为 2 的配置数组[start 配置, end 配置]单日期时两个槽位复用同一份配置adjustTimeForValue()再分别对start/end应用timeAdjust从而实现全天范围这类常见业务语义。五、Popover 弹层与自定义输入插槽要将选择器展示为弹层popover需要开发者通过默认插槽提供自己的内容最常见的就是一个input元素。⚠️ v2.0 破坏性变更v-date-picker不再默认渲染input元素该插槽必须由开发者提供同时inputPropsprop 已被废弃改为直接把输入值绑定到inputValue插槽变量上。5.1 基础输入框v-date-picker通过以下插槽变量开箱提供格式化、解析与事件处理inputValue应绑定到输入框的值。随着新日期被赋值与校验该值会自动更新。inputEvents包含最终会赋值新日期并管理弹层显隐由popoverprop 控制的一系列事件处理器。v-date-picker v-modeldate template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-picker5.2 范围双输入框绑定日期范围并提供自定义输入时inputValue与inputEvents会拆分为start/end两个子属性v-date-picker v-modelrange is-range template v-slot{ inputValue, inputEvents } div classflex justify-center items-center input :valueinputValue.start v-oninputEvents.start classborder px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300 / svg classw-4 h-4 mx-2 fillnone viewBox0 0 24 24 strokecurrentColor path stroke-linecapround stroke-linejoinround stroke-width2 dM14 5l7 7m0 0l-7 7m7-7H3 / /svg input :valueinputValue.end v-oninputEvents.end classborder px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300 / /div /template /v-date-pickerexport default { data() { return { range: { start: new Date(2020, 9, 12), end: new Date(2020, 9, 16), }, }; }, };从源码看slotArgsDatePicker.vue在is-range时把两个输入框的值与事件input/change/keyup以及弹层触发事件分别组装为start、end两组绑定后即可独立输入。5.3 输入防抖input-debounceinput-debounceprop毫秒设置文本输入的防抖时长。默认值为1000ms下面示例改为500ms以获得更快的响应v-date-picker v-modeldate :input-debounce500 template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-picker5.4 关闭输入即更新update-on-input默认update-on-input为true插件级默认值定义在 src/utils/defaults/index.js。设为false后用户输入过程中不再实时更新值而是等输入框的change事件触发时才更新v-date-picker v-modeldate :update-on-inputfalse template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-picker实现上onInputInput()DatePicker.vue会先检查updateOnInput_为假时直接忽略input事件只在change事件onInputChange时解析并更新值。5.5 输入格式化与解析默认使用当前 locale 的本地化格式对输入文本进行格式化与解析。v-date-picker与v-calendar一样接受显式localeprop适合从数据库读取用户 locale 或强制所有用户使用统一 locale 的场景v-date-picker v-modeldate :localelocale template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-pickerdata() { return { date: new Date(), locale: null, }; }, created() { // Fetch users locale using custom API (eg. en-ZA) this.locale await api.getUserLocale(); }若想用自定义掩码覆盖 locale 默认格式则设置masks.inputv-date-picker v-modeldate :masksmasks template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-pickerdata() { return { date: new Date(), masks: { input: YYYY-MM-DD, }, }; },关于掩码机制的更多细节默认掩码定义在 src/utils/defaults/masks.jsoninput系列掩码为数组如[L, YYYY-MM-DD, YYYY/MM/DD]即支持多种输入写法但第一个掩码负责格式化显示。掩码 token 的完整列表请参考 docs/format-parse-dates.md。5.6 完整表单示例下面是一个更复杂的示例自定义输入框 校验消息 清除按钮div classw-full max-w-sm form classbg-white shadow-md rounded px-8 pt-6 pb-8 submit.prevent label classblock text-gray-600 text-sm font-bold mb-2 fordate Select Date/label div classflex w-full v-date-picker v-modeldate classflex-grow template v-slot{ inputValue, inputEvents } input iddate classbg-white text-gray-700 w-full py-2 px-3 appearance-none border rounded-l focus:outline-none :class{ border-red-600: errorMessage } :valueinputValue v-oninputEvents / /template /v-date-picker button typebutton classtext-white font-bold py-2 px-4 rounded-r user-select-none focus:outline-none :classdate ? bg-red-500 : bg-red-300 :disabled!date clickdate null Clear /button /div p classtext-red-600 text-xs italic mt-1 v-iferrorMessage {{ errorMessage }} /p p classtext-blue-500 text-xs font-bold mt-1 v-else We got it. Thanks! /p /form /divexport default { data() { return { date: null, }; }, computed: { errorMessage() { if (!this.date) return Date is required.; return ; }, }, };5.7 高级插槽变量除了input其他元素同样可以作为默认插槽内容如按钮下拉、日期标签等更多参考 docs/examples/datepickers.md。默认插槽提供的全部变量如下PropTypeDescriptioninputValueObject输入文本值。inputEventsObject依据传给v-date-picker的 props 配置好的事件集包含input、change与keyupupdate-on-input、input-debounce等 props 会被正确处理。isDraggingBoolean用户正在拖拽选择新的范围时为true。updateValueFunction在你自己选择的时机调用以更新值。showPopoverFunction手动显示弹层。hidePopoverFunction手动隐藏弹层。togglePopoverFunction切换弹层显隐。getPopoverTriggerEventsFunction获取指定显示模式下可绑定的事件。updateValue(value, opts)调用updateValue(value, opts)可手动更新日期值并附带副作用选项。所有副作用都假定传入的 value 是合法的。 传入updateValue()的值会经过disabled-dates、available-dates、min-date、max-dateprops 的校验对应 DatePicker.vue 的valueIsDisabled()。ParameterTypeDescriptionDefault ValuevalueDate,String,Number新日期值undefinedopts.formatInputBoolean是否重新格式化inputValue。trueopts.hidePopoverBoolean是否隐藏弹层。falseopts.debounceNumber赋值前的防抖时长毫秒。undefinedopts.adjustPageRangeBoolean是否调整from-page以正确展示该值。undefined六、禁用日期、必填与选中态定制6.1 禁用日期v-date-picker的禁用能力与v-calendar完全一致支持min-date、max-date、disabled-dates、available-dates四种方式及其组合完整讲解见 docs/disable-dates.md。核心规则速览min-date/max-date显式限定可选边界同时会禁用边界之外月份的页面导航disabled-dates用日期表达式日期对象、范围对象、日期模式或它们的数组显式禁用例如{ weekdays: [1, 7] }禁用周末available-dates隐式启用——不在该范围内的日期全部禁用二者同时使用时先计算disabled-dates再由available-dates重新启用被显式禁用的日期available-dates指定的位于禁用范围之外的日期无效。在 tests/unit/specs/DatePicker.spec.js 中有对min-date/max-date的单元测试佐证最小日期之前、最大日期之后的日期格会带有is-disabled类点击后不会出现高亮选中态而边界日期本身可以选择。6.2 必填约束is-requiredis-requiredprop 会阻止用户通过删除输入框全部文本或再次点击选中日期来清空值v-date-picker v-modeldate is-required template v-slot{ inputValue, inputEvents } input classbg-white border px-2 py-1 rounded :valueinputValue v-oninputEvents / /template /v-date-picker其底层逻辑位于forceUpdateValue()DatePicker.vue归一化后的值为空且isRequired为真时会回退到上一次的值。对应测试DatePicker.spec.js验证了设置is-required后重复点击同一日期高亮保持存在未设置时再次点击可清除选中。注意is-required仅限制用户交互代码中直接赋值value null仍然有效见 docs/api/v2.0/datepicker.md 的说明。6.3 定制选中样式select-attribute 与 drag-attributev-date-picker使用以下两个 props 展示日期选中状态AttributeDescriptionselect-attribute表示已选中值的 attribute。drag-attribute表示拖拽中的值的 attribute仅在mode range即is-range时有效。传入自定义 attribute 对象即可整体替换默认样式默认值为高亮highlight。两个 attribute 都被分配了相同的 keyselect-drag。例如想把选中态从高亮改成圆点dotv-date-picker v-modeldate :select-attributeselectAttribute /export default { data() { return { date: new Date(), selectAttribute: { dot: true, }, }; }, };从源码看DatePicker.vue组件会把你的自定义对象与key: select-drag、dates: 当前值、pinPage: true等合并若自定义对象中既没有dot、bar、highlight也没有content则自动补充highlight: true作为兜底drag-attribute的兜底则是highlight: { startEnd: { fillMode: outline } }的描边样式。6.4 选中范围的弹出提示最后看一个综合示例为拖拽中和已选中的范围添加简单弹层。注意这里使用了day-popover插槽并确保 attribute 的popover属性为真值显示优先级为先展示拖拽中的范围再回退到已选中范围v-date-picker v-modelrange :select-attributeselectDragAttribute :drag-attributeselectDragAttribute is-range dragdragValue $event template v-slot:day-popover{ format } div {{ format(dragValue ? dragValue.start : range.start, MMM D) }} - {{ format(dragValue ? dragValue.end : range.end, MMM D) }} /div /template /v-date-pickerexport default { data() { return { dragValue: null, range: { start: new Date(2018, 0, 8), end: new Date(2018, 0, 12), }, }; }, computed: { selectDragAttribute() { return { popover: { visibility: hover, isInteractive: false, // 使用插槽时默认为 true }, }; }, }, };此处drag事件在拖拽过程中持续派发源码中forceUpdateValue()在拖拽态下把事件名切换为drag见 DatePicker.vueday-popover插槽中的format函数则来自v-calendar的 locale 格式化能力可安全地用于拼装提示文案。七、源码透视一次值更新的完整流水线理解 DatePicker.vue 的forceUpdateValue()就能把握v-date-picker的核心行为。它按以下步骤处理每一次赋值归一化NormalizationnormalizeValue()根据model-config的typedate/string/number/object/auto与mask把外部值统一转为内部Date范围模式下自动交换start/end并依据rangePriority决定保留哪一端。必填回退若结果为null且is-required回退到旧值。时间调整adjustTimeForValue()应用timeAdjust、valid-hours就近取整与minute-increment就近取整。校验ValidationvalueIsDisabled()检查是否命中disabled-dates/available-dates/min-date/max-date命中则拒绝赋值拖拽中则直接忽略。赋值与通知比较新旧值发生变化时写入value_或拖拽中的dragValue随后通过denormalizeValue()反归一化字符串格式化、数字转时间戳再派发input或drag事件。收尾按需隐藏弹层、重新格式化输入框文本。另外值的更新还经过了PATCHlocale.js机制的补丁合并DATE_TIME补丁只覆盖年月日时分秒等时间部件DATE补丁只覆盖年月日TIME补丁只覆盖时分秒毫秒——这就是选新日期保留旧时间、mode: time时保留既有日期部分的行为来源。输入框掩码还会自动判断包含日期还是时间inputMaskPatchDatePicker.vue从而选择正确的补丁类型。上述行为均有单元测试覆盖可在 tests/unit/specs/DatePicker.spec.js 中找到value时间设置、min-date/max-date边界、is-required清空语义、model-config.fillDate补全日期、timeAdjust、valid-hours三种形态等用例可作为你自行扩展行为的参考基线。八、组件方法速查通过ref可以调用v-date-picker暴露的方法需在mounted及之后调用v-date-picker refdatepicker /mounted() { const datepicker this.$refs.datepicker; datepicker.move(new Date()); }move(Number|String|Date|Object)异步地按月份数、跳转到某月或某日期内部调用Calendar.movedocs/api/v2.0/calendar.md。focusDate(String|Date)异步跳转并聚焦某天内部调用Calendar.focusDate。此外组件还透传input新日期已选择、drag拖拽范围更新仅is-range时、popoverWillShow/popoverDidShow/popoverWillHide/popoverDidHide等事件完整列表见 docs/api/v2.0/datepicker.md 的 Events 章节。结语v-date-picker把日历渲染、范围拖拽、时间选择、输入格式化/解析、弹层管理与数据格式适配整合在一个组件中配合mode、is-range、model-config与自定义默认插槽几乎可以覆盖表单场景下从纯日期单选到带时间范围的双输入框的全部需求。结合 DatePicker.vue 与 locale.js 的源码你可以清晰地预测组件在边界条件下的行为如分钟取整、时区处理、必填回退、禁用校验从而把更多精力放在业务交互本身。赞分享前端UI组件【免费下载链接】v-calendarAn elegant calendar and datepicker plugin for Vue.项目地址https://gitcode.com/gh_mirrors/vc/v-calendar点击查看免费下载相关推荐终极V-Calendar日期选择器教程从单日期到日期范围的完美实现终极V Calendar日期选择器教程从单日期到日期范围的完美实现 V Calendar是一款优雅的Vue日期选择器插件提供了单日期选择、多日期选择和日期范前端UI组件all-in-rag 食谱知识库实战酸梅汤半成品加工结构化食谱在 RAG 问答系统中的应用all in rag 食谱知识库实战酸梅汤半成品加工结构化食谱在 RAG 问答系统中的应用 酸梅汤半成品加工是一道基于酸梅晶固体饮料速成的家常饮品前端UI组件Mac Mouse Fix 鼠标增强完全指南把普通鼠标用到接近触控板Mac Mouse Fix 鼠标增强完全指南把普通鼠标用到接近触控板 Mac Mouse Fix 是一个 macOS 鼠标增强工具通过系统级输入接管给你的桌面应用系统编程上一篇react-admin 实时事件订阅 Hook useSubscribe 完整指南下一篇PeerTube 测试开发指南从环境准备到服务端与 E2E 测试的完整实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表