赞
踩
由于在数据项目中经常以各种时间条件查询数据,所以时间选择器(DatePicker)组件是很常用的组件。但是在我使用的 Element UI 中,缺少了季度选择器的功能。
一开始我根据时间范围使用 select 去遍历,如 2024-Q1、2023-Q4、2023-Q3 如此类推。
其实也算是快速解决了 element ui 无法选择季度的问题。但总感觉特别的 low,后来有时间了就去隔壁 ant design 看了看。
发现在新版的 ant design 都支持季度和季度范围选择器了……
查了查新的 element plus 也只是只支持了 'year' | 'years' |'month' | 'date' | 'dates' | 'datetime' | 'week' | 'datetimerange' | 'daterange' | 'monthrange'
这些个类型。
工具不给力,又不想用其他库的情况下只能手搓了。
参考 ant design 做了一个类似的面板。
<template> <div class="quarter-panel"> <div class="quarter-panel-header"> <i class="quarter-panel-header-icon el-icon-arrow-left" @click="currentYear--" /> <div class="quarter-panel-header-title">{{ currentYear }} 年</div> <i class="quarter-panel-header-icon el-icon-arrow-right" @click="currentYear++" /> </div> <div class="quarter-panel-content"> <div v-for="option in quarterOptions" class="quarter-panel-item-btn" :class="getComputedClass(option.value)" :key="option.value" @click="emitClick(option.value)" > {{ option.label }} </div> </div> </div> </template> <script> import dayjs from 'dayjs' import customParseFormat from 'dayjs/plugin/customParseFormat' dayjs.extend(customParseFormat) export default { name: 'QuarterPanel', props: { value: String, dice: Number, min: String, max: String, todayDisabled: Boolean, featureDisabled: Boolean, }, data() { return { currentYear: 2023, } }, computed: { day() { if (this.value) { return dayjs(this.value, 'YYYY-MM-DD') } return dayjs() }, computedDate() { return this.day.startOf('quarter').format('YYYY-MM-DD') }, quarterOptions() { return [ { label: 'Q1', value: `${this.currentYear}-01-01` }, { label: 'Q2', value: `${this.currentYear}-04-01` }, { label: 'Q3', value: `${this.currentYear}-07-01` }, { label: 'Q4', value: `${this.currentYear}-10-01` }, ] }, }, mounted() { this.currentYear = dayjs().year() }, methods: { getDisabled(value) { let isFeature = false if (this.todayDisabled) { isFeature = dayjs() .subtract(1, 'day') .startOf('quarter') .isBefore(dayjs(value)) } else if (this.featureDisabled) { isFeature = dayjs().startOf('quarter').isBefore(dayjs(value)) } const isMin = this.min ? dayjs(this.min, 'YYYY-MM-DD') .startOf('quarter') .isAfter(dayjs(value, 'YYYY-MM-DD')) : false const isMax = this.max ? dayjs(this.max, 'YYYY-MM-DD') .startOf('quarter') .isBefore(dayjs(value, 'YYYY-MM-DD')) : false return isFeature || isMin || isMax }, getComputedClass(value) { if (this.computedDate === value) { return 'quarter-panel-item-btn-active' } if (this.getDisabled(value)) { return 'quarter-panel-item-btn-disabled' } return '' }, emitClick(value) { if (this.getDisabled(value)) { return } this.$emit('input', value) }, }, watch: { dice() { this.currentYear = this.day.year() }, }, } </script> <style lang="scss" scoped> $--gw-primary-color: #f6674f; .quarter-panel { width: 200px; color: #303133; .quarter-panel-header { height: 30px; padding: 12px; display: flex; align-items: center; .quarter-panel-header-icon { font-size: 12; margin: 5px; cursor: pointer; &:hover { color: $--gw-primary-color; } } .quarter-panel-header-title { flex: 1; text-align: center; font-size: 16; } } .quarter-panel-content { display: flex; align-items: center; .quarter-panel-item-btn { flex: 1; font-size: 14; height: 30px; line-height: 30px; text-align: center; cursor: pointer; border: solid 1px transparent; border-radius: 5px; &:hover { color: $--gw-primary-color; border: solid 1px $--gw-primary-color; } } .quarter-panel-item-btn-active { background: $--gw-primary-color; color: #ffffff; &:hover { color: #ffffff; } } .quarter-panel-item-btn-disabled { color: #909399; background: #f2f6fc; cursor: not-allowed; &:hover { color: #909399; background: #f2f6fc; } } } } </style>
将面板放到 el-popover
中实现类似 DatePicker 的效果。并且提供了像清空数据、最大值、最小值等常用功能。
<template> <div class="quarter-picker" :class="{ 'quarter-picker-disabled': disabled }"> <div class="quarter-picker-date-button"> <i class="iconfont icon-date-select-icon quarter-picker-time-icon" /> <el-popover placement="bottom-start" width="200" trigger="click" ref="datePopover" :disabled="disabled" @show="initPopover" > <div class="quarter-picker-date-button-item quarter-picker-date-button-item-long" slot="reference" > <span v-if="form.date" class="button-item-span"> {{ dateQuarterStr }} </span> <span v-else class="button-item-span">选择时间</span> <div class="bottom-line" /> </div> <quarterPanel v-model="form.date" :dice="dice" :min="min" :max="max" :featureDisabled="featureDisabled" :todayDisabled="todayDisabled" @input="emitDateChange()" /> </el-popover> <i v-show="form.date && clearable" class="el-icon-close quarter-picker-clear-icon" @click.stop="clearCurrentDate" /> </div> </div> </template> <script> import dayjs from 'dayjs' import customParseFormat from 'dayjs/plugin/customParseFormat' import quarterOfYear from 'dayjs/plugin/quarterOfYear' import quarterPanel from './quarterPanel.vue' dayjs.extend(customParseFormat) dayjs.extend(quarterOfYear) /** * date 日期 */ export default { name: 'QuarterPicker', components: { quarterPanel, }, props: { date: String, min: String, max: String, featureDisabled: Boolean, todayDisabled: Boolean, disabled: Boolean, clearable: Boolean, }, data() { return { form: { date: '', }, dice: 0, } }, mounted() { this.syncData() }, computed: { dateQuarterStr() { if (!this.form.date) return '选择季' const dj = dayjs(this.form.date).startOf('quarter') return `${dj.year()}-Q${dj.quarter()}` }, }, methods: { initPopover() { this.dice++ }, syncData() { this.form.date = this.date }, clearCurrentDate() { if (this.disabled) return this.form.date = '' this.emitDateChange() }, emitDateChange() { this.$emit('change', this.form) this.closePopovers() }, closePopovers() { this.$refs.datePopover.doClose() }, }, watch: { date() { if (this.form.date !== this.date) { this.syncData() } }, }, } </script> <style scoped lang="scss"> $--gw-primary-color: #f6674f; .quarter-picker { display: flex; flex-direction: row; align-items: center; justify-content: flex-end; .quarter-picker-date-button { display: flex; position: relative; flex-direction: row; align-items: center; justify-content: center; user-select: none; margin-left: 5px; width: 250px; padding-left: 10px; height: 28px; background: #ffffff; border: 1px solid #dcdfe6; font-size: 14px; font-family: Microsoft YaHei; font-weight: 400; color: #282c32; border-radius: 4px; .quarter-picker-time-icon { position: absolute; left: 12px; } .quarter-picker-date-button-item { position: relative; height: 28px; line-height: 28px; text-align: center; width: 70px; cursor: pointer; .bottom-line { position: absolute; bottom: 0; left: 0; right: 0; height: 2px; border-radius: 1px; background: transparent; } &:hover { .bottom-line { background: $--gw-primary-color; } } } .quarter-picker-date-button-item-long { width: 200px; .button-item-span { display: inline-block; width: 90px; text-align: center; } .button-item-span-active { color: $--gw-primary-color; } } .quarter-picker-clear-icon { position: absolute; right: 12px; font-size: 14; cursor: pointer; &:hover { color: $--gw-primary-color; } } } } .quarter-picker-disabled { .quarter-picker-date-button { color: #c0c4cc; background-color: #f2f6fc; .quarter-picker-date-button-item { cursor: not-allowed; } } .quarter-picker-date-button-item { &:hover { .bottom-line { background: transparent !important; } } } .quarter-picker-clear-icon { cursor: not-allowed !important; &:hover { color: #c0c4cc !important; } } } </style>
最后就是组件的使用了:
<QuarterPicker
type="quarter"
:date="quarter.date"
:min="minDate"
:max="maxDate"
:featureDisabled="options.featureDisabled"
:todayDisabled="options.todayDisabled"
:disabled="options.disabled"
:clearable="options.clearable"
@change="handleQuarterPickerChange"
/>
handleQuarterPickerChange({ date }) {
this.quarter.date = date
this.$message({
message: '触发查询请求',
type: 'success',
})
},
另外,季度范围选择器也可以用类似的思路来实现。以上就是个人解决季度选择器的方式。希望能对有类似需求的同学一些帮助。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。