更新效果图
组件包地址el-data-picker季度区间选择器-Javascript文档类资源-CSDN下载使用方式不变,下载之后放在项目文件夹内直接引入即可
-----------------------分割线-----------------------
效果
1. element-ui版本号2.15.8,2.15.7el-data-picker会报错。该季度区间选择器会用到的插件只有dayjs,安装完dayjs之后直接引入以下组件使用即可
config.js
// 季节对应筛选项
export const quarter_options = [
{
label: 'Q1',
value: 1,
months: [1, 2, 3]
},
{
label: 'Q2',
value: 2,
months: [4, 5, 6]
},
{
label: 'Q3',
value: 3,
months: [7, 8, 9]
},
{
label: 'Q4',
value: 4,
months: [10, 11, 12]
}
];
/**
* 获取季度对应的月份
* @returns
*/
export function getQuarterOptionMonths(value) {
for (let item of quarter_options) {
if (item.value == value) {
return item.months;
}
}
}
/**
* 获取日期对应季度
* @returns
*/
export function getQuarterItemOfMonth(month) {
for (let item of quarter_options) {
if (item.months.includes(month)) {
return item;
}
}
}
index.vue
<template>
<div class="quarter-range-picker">
<!-- 透明遮罩 -->
<div class="mark"
v-if="show_quarter_range_picker"
@click.stop="handleClosePicker"></div>
<!-- 结果显示框 -->
<el-date-picker :value="showValue"
popper-class="quarter-range-picker-date-popper"
type="monthrange"
format="yyyy-QM"
class="mo-date-picker"
range-separator="至"
@focus="handleOpenPicker"
size="mini"
@change="handleChange"
start-placeholder="开始季度"
end-placeholder="结束季度">
</el-date-picker>
<!--
<el-input placeholder="请选择季度"
:value="showValue"
style="width: 240px"
@focus="focusClick"
size="mini">
<i slot="prefix"
class="el-input__icon el-icon-date"></i> -->
<!-- </el-input> -->
<!-- 弹出选框 -->
<el-collapse-transition>
<el-card class="quarter-range-picker__box-card"
v-show="show_quarter_range_picker">
<div class="quarter-range-picker__content">
<QuarterPicker :year.sync="start_year"
:quarter="start_quarter"
:showRight="start_show_right"
@on-quarter-click="handleStartQuarterClick"
@on-year-change="handleStartYearChange"></QuarterPicker>
<QuarterPicker :year.sync="end_year"
:showLeft="end_show_left"
:quarter.sync="end_quarter"
@on-quarter-click="handleEndQuarterClick"
@on-year-change="handleEndYearChange"></QuarterPicker>
</div>
</el-card>
</el-collapse-transition>
</div>
</template>
<script>
/**
* 季节选择组件
*/
import QuarterPicker from "./quarter-picker.vue"
import dayjs from 'dayjs';
import { getQuarterOptionMonths } from './config.js';
export default {
name: 'mo-quarter-range-picker',
components: {
QuarterPicker
},
props: {
// [起始日期,结束日期]
value: {
type: Array,
default: null,
},
},
data() {
let now = dayjs();
return {
show_quarter_range_picker: false,
// 开始
start_year: now.year(),
start_quarter: [],
// 结束
end_year: now.year() + 1,
end_quarter: [],
// 整合后的月份 {year, quarter}
quarter: []
}
},
computed: {
start_show_right() {
return this.start_year < this.end_year - 1;
},
end_show_left() {
return this.end_year > this.start_year + 1;
},
showValue() {
if (this.value) {
console.log(this.value);
let start_date = dayjs(this.value[0])
let end_date = dayjs(this.value[1])
return [`${start_date.year()}-${start_date.quarter()}`, `${end_date.year()}-${end_date.quarter()}`]
} else {
return null
}
},
},
created() {
},
methods: {
handleOpenPicker() {
let start_date = dayjs()
let end_date = dayjs().add(1, 'years');
if (this.value) {
start_date = dayjs(this.value[0])
end_date = dayjs(this.value[1])
this.start_quarter = [`${start_date.year()}-${start_date.quarter()}`, `${end_date.year()}-${end_date.quarter()}`]
this.end_quarter = [`${start_date.year()}-${start_date.quarter()}`, `${end_date.year()}-${end_date.quarter()}`]
}
this.start_year = start_date.year()
// 结束
this.end_year = end_date.year()
if (this.start_year >= this.end_year) {
this.end_year = this.start_year + 1;
}
// 清空已选中
this.quarter.splice(0, this.quarter.length);
this.show_quarter_range_picker = true
},
handleClosePicker() {
this.show_quarter_range_picker = false;
},
handleStartYearChange(year) {
this.start_year = year
},
handleStartQuarterClick(quarter_item) {
if (this.quarter.length == 0) {
this.start_quarter.splice(0, this.start_quarter.length);
this.end_quarter.splice(0, this.end_quarter.length);
}
let index = this.start_quarter.indexOf(quarter_item.value);
if (index > -1) {
this.start_quarter.splice(index, 1);
} else {
this.start_quarter.push(quarter_item.value)
}
this.quarter.push(quarter_item)
this.handleCheckQuarterRange();
},
handleEndQuarterClick(quarter_item) {
if (this.quarter.length == 0) {
this.start_quarter.splice(0, this.start_quarter.length);
this.end_quarter.splice(0, this.end_quarter.length);
}
let index = this.end_quarter.indexOf(quarter_item.value);
if (index > -1) {
this.end_quarter.splice(index, 1);
} else {
this.end_quarter.push(quarter_item.value)
}
this.quarter.push(quarter_item)
console.log(this.quarter);
this.handleCheckQuarterRange();
},
handleCheckQuarterRange() {
// console.log('quarter', this.quarter);
if (this.quarter.length == 2) {
// 排序
this.quarter.sort((a, b) => {
if (a.year == b.year) {
return a.quarter - b.quarter
} else {
return a.year - b.year
}
})
let result = [];
for (let item of this.quarter) {
// 开始日期
// let start_quarter = this.quarter[0];
let months = getQuarterOptionMonths(item.quarter);
let start_quarter_month = months[0];
let end_quarter_month = months[months.length - 1];
// 月份从 0 开始索引
let start_date = dayjs(`${item.year}-${start_quarter_month}`).startOf("month").format('YYYY-MM-DD')
let end_date = dayjs(`${item.year}-${end_quarter_month}`).endOf("month").format('YYYY-MM-DD')
result.push({
...item,
start_date,
end_date
})
}
// console.log('result', [result[0].start_date, result[1].end_date]);
this.$emit('update:value', [result[0].start_date, result[1].end_date])
this.$emit('on-change', result)
this.show_quarter_range_picker = false;
}
},
handleEndYearChange() {
// this.end_quarter.splice(0, this.start_quarter.length);
},
handleChange(val) {
// console.log('handleClear', val);
// 清空操作
if (!val) {
this.start_quarter.splice(0, this.start_quarter.length);
this.end_quarter.splice(0, this.end_quarter.length);
this.$emit('update:value', null)
}
},
},
}
</script>
<style lang="less">
.mark {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
z-index: 999;
}
.quarter-range-picker {
display: inline-block;
position: relative;
.el-card__body {
padding: 0;
}
.quarter-range-picke__value {
position: absolute;
left: 0;
right: 0;
width: 100%;
height: 100%;
}
}
.quarter-range-picker__box-card {
// width: 500px;
// padding: 0 3px 20px;
margin-top: 10px;
position: absolute;
z-index: 9999;
}
.quarter-range-picker__content {
display: flex;
justify-content: space-between;
}
// 隐藏原有的选择器
.quarter-range-picker-date-popper {
display: none;
}
</style>
<style scoped>
</style>
quarter-picker.vue
<template>
<div class="quarter-picker">
<div class="quarter-picker-inner">
<div class="quarter-picker__header">
<!-- 左边按钮 -->
<i class="el-icon-d-arrow-left" @click="handlePrevYear" v-if="showLeft"></i>
<span v-else class="empty-arrow"></span>
<div class="quarter-picker__title">{{ year }}</div>
<!-- 右边按钮 -->
<i class="el-icon-d-arrow-right" @click="handleNextYear" v-if="showRight"></i>
<span v-else class="empty-arrow"></span>
</div>
<div class="quarter-picker__options">
<template v-for="item in options">
<div class="quarter-picker__item" v-bind:key="item.value" :data-value="item.value" @click="handleItemClick(item)" :class="{
'quarter-picker__item__today': item.value == now_quarter,
'quarter-picker__item--active': quarter.includes(item.value),
}">
<div class="quarter-picker__item__label">{{ item.label }}</div>
</div>
</template>
</div>
</div>
</div>
</template>
<script>
// created at 2022-04-22
import dayjs from 'dayjs'
import { quarter_options } from './config.js'
var quarterOfYear = require('dayjs/plugin/quarterOfYear')
dayjs.extend(quarterOfYear)
export default {
name: 'quarter-picker',
props: {
// 当前年
year: {
type: Number,
default: () => {
return dayjs().year()
}
},
// 当前季度 ['2022-1']
quarter: {
type: Array,
default: () => {
return []
}
},
// 当前日期
// value: {
// type: Array,
// default: () => { return [] },
// },
// 显示左边按钮
showLeft: {
type: Boolean,
default: true
},
// 显示右边按钮
showRight: {
type: Boolean,
default: true
}
},
components: {},
data() {
let now = dayjs()
let now_year = now.year()
let now_quarter = `${now_year}-${now.quarter()}`
return {
now_year,
now_quarter
}
},
computed: {
options() {
return quarter_options.map((item) => {
return {
label: item.label,
value: `${this.year}-${item.value}`,
year: this.year,
quarter: item.value
}
})
}
},
methods: {
async getData() {},
handleItemClick(item) {
this.$emit('on-quarter-click', item)
},
handlePrevYear() {
let year = this.year - 1
this.$emit('update:year', year)
this.$emit('on-year-change', year)
},
handleNextYear() {
let year = this.year + 1
this.$emit('update:year', year)
this.$emit('on-year-change', year)
}
},
created() {
this.getData()
console.log(this.quarter)
}
}
</script>
<style lang="less">
.quarter-picker {
border-right: 1px solid #e5e6eb;
}
.quarter-picker-inner {
padding: 8px 16px;
}
.quarter-picker__header {
display: flex;
justify-content: space-between;
font-size: 12px;
// padding: 8px 16px;
border-bottom: 1px solid #e5e6eb;
.el-icon-d-arrow-left,
.el-icon-d-arrow-right,
.empty-arrow {
cursor: pointer;
width: 24px;
height: 24px;
font-size: 12px;
line-height: 24px;
text-align: center;
border-radius: 50%;
transition: all 0.1s cubic-bezier(0, 0, 1, 1);
user-select: none;
&:hover {
background-color: #e5e6eb;
}
}
.empty-arrow {
cursor: auto;
&:hover {
background-color: transparent;
}
}
.quarter-picker__title {
flex: 1;
color: #1d2129;
font-size: 14px;
line-height: 24px;
text-align: center;
}
}
.quarter-picker__options {
display: grid;
grid-template-columns: repeat(4, 1fr);
padding: 14px 16px;
}
.quarter-picker__item {
padding: 4px;
cursor: pointer;
position: relative;
}
.quarter-picker__item__label {
border-radius: 24px;
color: #000;
background-color: #fff;
// font-weight: 500;
height: 24px;
font-size: 14px;
line-height: 24px;
text-align: center;
width: 50px;
}
.quarter-picker__item--active .quarter-picker__item__label,
.quarter-picker__item:hover .quarter-picker__item__label {
background-color: #409eff;
color: #fff;
}
.quarter-picker__item__today:after {
position: absolute;
bottom: -2px;
left: 50%;
display: block;
width: 4px;
height: 4px;
margin-left: -2px;
background-color: #409eff;
border-radius: 50%;
content: '';
}
</style>
<style lang="less" scoped>
</style>
2. 使用以上组件
<quarterPicker :value.sync="searchForm.shop" @on-change="handleChange"></quarterPicker>
import quarterPicker from '@/components/quarter-range-picker/index'
handleChange(value) {
console.log(this.value)
console.log(value)
},