一、在项目 components
路径下创建 quarter-picker
文件夹
1 <!-- 2 * @Descripttion: 季度选择器 3 * @version: 1.0 4 * @Author: https://www.lervor.com/ 5 * @Date: 2021-12-06 6 * @LastEditTime: 2021-12-09 7 --> 8 <template> 9 <el-popover 10 trigger="focus" 11 v-model="pickerVisible" 12 popper-class="lervor-quarter-popover" 13 :disabled="disabled"> 14 <el-input 15 ref="reference" 16 slot="reference" 17 class="el-date-editor" 18 readonly 19 :disabled="disabled" 20 :size="size" 21 :placeholder="placeholder" 22 :value="displayValue" 23 :validate-event="false" 24 :style="{ width }" 25 @mouseenter.native="handleMouseEnter" 26 @mouseleave.native="showClose = false"> 27 <i slot="prefix" 28 class="el-input__icon" 29 :class="triggerClass"> 30 </i> 31 <i slot="suffix" 32 class="el-input__icon" 33 :class="[showClose ? '' + clearIcon : '']" 34 @click="handleClickIcon" 35 @mousedown="handleMousedownIcon"> 36 </i> 37 </el-input> 38 <div class="lervor-quarter-picker"> 39 <div class="el-date-picker__header el-date-picker__header--bordered"> 40 <button 41 type="button" 42 aria-label="前一年" 43 class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left" 44 @click="prevYear"> 45 </button> 46 <span 47 role="button" 48 class="el-date-picker__header-label">{{ yearLabel }}</span> 49 <button 50 type="button" 51 aria-label="后一年" 52 class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right" 53 @click="nextYear"> 54 </button> 55 </div> 56 <div class="el-picker-panel__content" style="width: 200px; margin: 10px 15px;"> 57 <table class="lervor-quarter-table" @click="handleTableClick"> 58 <tbody> 59 <tr> 60 <td class="available" :class="getCellStyle(0)"> 61 <a class="cell">第一季度</a> 62 </td> 63 <td class="available" :class="getCellStyle(1)"> 64 <a class="cell">第二季度</a> 65 </td> 66 </tr> 67 <tr> 68 <td class="available" :class="getCellStyle(2)"> 69 <a class="cell">第三季度</a> 70 </td> 71 <td class="available" :class="getCellStyle(3)"> 72 <a class="cell">第四季度</a> 73 </td> 74 </tr> 75 </tbody> 76 </table> 77 </div> 78 </div> 79 </el-popover> 80 </template> 81 82 <script> 83 import { formatDate, prevYear, nextYear, range, nextDate, isDateObject, parseDate } from 'element-ui/src/utils/date-util' 84 import { hasClass } from 'element-ui/src/utils/dom' 85 86 // 获取指定年份和季度的所有日期 87 const datesInYearAndQuarter = (year, quarter) => { 88 const numOfDays = getDayCountOfQuarter(year, quarter) 89 const firstDay = new Date(year, quarter * 3, 1) 90 return range(numOfDays).map(n => nextDate(firstDay, n)) 91 } 92 93 // 获取指定年份和季度总天数 94 const getDayCountOfQuarter = (year, quarter) => { 95 switch(quarter) { 96 case 0: // 第一季度包含二月,需要对是否闰年进行判断处理 97 if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) { 98 return 91 99 } else { 100 return 90 101 } 102 case 1: 103 return 91 104 default: 105 return 92 106 } 107 } 108 109 export default { 110 name: 'QuarterPicker', 111 props: { 112 size: String, 113 format: String, // 显示在输入框中的格式,引入季度:q(阿拉伯数字)、Q(中文数字) 114 valueFormat: String, 115 placeholder: String, 116 prefixIcon: String, 117 clearIcon: { 118 type: String, 119 default: 'el-icon-circle-close' 120 }, 121 disabled: Boolean, 122 clearable: { 123 type: Boolean, 124 default: true 125 }, 126 width: { // 组件宽度 127 type: String, 128 default: '' 129 }, 130 disabledDate: {}, // 不可用的日期 131 value: null 132 }, 133 data() { 134 return { 135 showClose: false, 136 pickerVisible: false, 137 date: new Date(), 138 quarterText: [ '一', '二', '三', '四' ] 139 } 140 }, 141 computed: { 142 triggerClass() { 143 return this.prefixIcon || 'el-icon-date' 144 }, 145 displayValue() { 146 if (!this.value) return null 147 // 季度,从0开始 148 const quarter = parseInt(this.parsedValue.getMonth() / 3) 149 let fDate = formatDate(this.parsedValue, this.format) 150 fDate = fDate.replace(/q/, quarter + 1).replace(/Q/, this.quarterText[quarter]) 151 return fDate 152 }, 153 year() { 154 return this.date.getFullYear() 155 }, 156 yearLabel() { 157 return this.year + ' 年' 158 }, 159 parsedValue() { 160 if (!this.value) { 161 return this.value 162 } 163 if (isDateObject(this.value)) { 164 return this.value 165 } 166 // 非时间格式且设置了valueFormat,进行时间转换 167 if (this.valueFormat) { 168 return parseDate(this.value, this.valueFormat) 169 } 170 // 非时间格式且未设置valueFormat,再尝试转换时间 171 return new Date(this.value) 172 } 173 }, 174 watch: { 175 value(value) { 176 this.date = value ? this.parsedValue : new Date() 177 } 178 }, 179 methods: { 180 handleMouseEnter() { 181 if (this.disabled) return 182 if (this.value && this.clearable) { 183 this.showClose = true 184 } 185 }, 186 handleClickIcon(event) { 187 if (this.disabled) return 188 if (this.showClose) { 189 this.$emit('input', null) 190 this.$emit('change', null) 191 this.showClose = false 192 this.pickerVisible = false 193 this.$refs.reference.blur() 194 } 195 }, 196 handleMousedownIcon(event) { 197 // 阻止鼠标按下清空按钮,防止清空数据时季度选择面板闪现 198 event.preventDefault() 199 }, 200 handleTableClick(event) { 201 let target = event.target 202 if (target.tagName === 'A') { 203 target = target.parentNode 204 } 205 if (target.tagName !== 'TD') return 206 if (hasClass(target, 'disabled')) return 207 const column = target.cellIndex 208 const row = target.parentNode.rowIndex 209 // 季度,从0开始 210 const quarter = row * 2 + column 211 // 季度开始月份,从0开始 212 const month = quarter * 3 213 let newDate = new Date(this.year, month, 1) 214 if (this.valueFormat) { 215 newDate = formatDate(newDate, this.valueFormat) 216 } 217 this.pickerVisible = false 218 this.$emit('input', newDate) 219 this.$emit('change', newDate) 220 }, 221 prevYear() { 222 this.date = prevYear(this.date) 223 }, 224 nextYear() { 225 this.date = nextYear(this.date) 226 }, 227 getCellStyle(quarter) { 228 const style = {} 229 const today = new Date() 230 const date = this.parsedValue ? this.parsedValue : today 231 style.disabled = typeof this.disabledDate === 'function' 232 ? datesInYearAndQuarter(this.year, quarter).every(this.disabledDate) : false 233 // 当前选中的季度样式 234 style.current = date.getFullYear() === this.year && parseInt(date.getMonth() / 3) === quarter 235 // 今日所在季度样式 236 style.quarter = today.getFullYear() === this.year && parseInt(today.getMonth() / 3) === quarter 237 return style 238 } 239 } 240 } 241 </script> 242 243 <style> 244 .lervor-quarter-picker { 245 line-height: 30px; 246 } 247 .lervor-quarter-popover { 248 padding: 0; 249 } 250 .lervor-quarter-table { 251 font-size: 12px; 252 margin: -1px; 253 border-collapse: collapse; 254 width: 100%; 255 } 256 .lervor-quarter-table td { 257 text-align: center; 258 padding: 10px 3px; 259 cursor: pointer; 260 } 261 .lervor-quarter-table td .cell { 262 height: 32px; 263 display: block; 264 line-height: 32px; 265 color: #606266; 266 margin: 0 auto; 267 } 268 .lervor-quarter-table td .cell:hover { 269 color: #1890ff; 270 } 271 272 .lervor-quarter-table td.current:not(.disabled) .cell { 273 color: #409eff; 274 } 275 276 .lervor-quarter-table td.quarter .cell { 277 color: #409eff; 278 font-weight: 700; 279 } 280 281 .lervor-quarter-table td.disabled .cell { 282 background-color: #F5F7FA; 283 cursor: not-allowed; 284 color: #C0C4CC; 285 } 286 </style>View Code
二、创建 index.vue
文件
1 <template> 2 <div> 3 <quarter-picker 4 width="150px" 5 format="yyyy年q季度" 6 value-format="yyyyMM" 7 placeholder="选择季度" 8 v-model="quarterDate" 9 :disabled-date="disabledQuarter" 10 @change="handleChangeQuarter" /> 11 </div> 12 </template> 13 14 <script> 15 import QuarterPicker from '@/components/quarter-picker' 16 export default { 17 components: { 18 QuarterPicker 19 }, 20 data() { 21 return { 22 quarterDate: '202104', 23 // 禁用日期/季度示例,只允许选择本年度本季度(不含)之前的季度 24 disabledQuarter: time => { 25 const now = new Date() 26 return time.getFullYear() > now.getFullYear() || time.getFullYear() === now.getFullYear() && parseInt(time.getMonth() / 3) >= parseInt(now.getMonth() / 3) 27 } 28 } 29 }, 30 methods: { 31 handleChangeQuarter(date) { 32 console.info(date) 33 } 34 } 35 } 36 </script>View Code
最终效果:
代码参考:https://www.lervor.com/archives/244/
标签:return,ElementUI,QuarterPicker,value,year,date,const,quarter,选择器 From: https://www.cnblogs.com/zyn123/p/16832750.html