vue3 + element-plus 季度选择器组件
...大约 3 分钟
vue3 + element-plus 季度选择器组件
背景
项目中要搞一个季度选择器,但是 element-plus 没有,所以网上搜索了一个大神写的,记录一下,方便以后使用。
一、复制下面代码,到 ElQuarterPicker.vue 页面中
<template>
<div class="el-quarter-wrap">
<el-popover title="" content="" width="320" v-model="visible">
<template #reference>
<el-input
v-model="quarterDate"
placeholder="请选择季度"
clearable
:prefix-icon="Calendar"
readonly
@click.stop.native="visible = true"
@change="quarterDateChange">
<template #suffix>
<el-icon
v-if="quarterDate"
class="el-quarter-clear"
@click="clearData">
<Close />
</el-icon>
</template>
</el-input>
</template>
<div class="el-quarter__header">
<span
class="el-quarter-btn el-quarter-btn__pre"
@click="changeShowYear(-1)">
<el-icon>
<DArrowLeft />
</el-icon>
</span>
<div class="el-quarter__header-text" @click="showYearList">
{{ quarterTitle }}
</div>
<span
class="el-quarter-btn el-quarter-btn__next"
@click="changeShowYear(1)">
<el-icon>
<DArrowRight />
</el-icon>
</span>
</div>
<div class="el-quarter__content" v-if="!isEditYear">
<div class="el-quarter__row">
<span
class="quarter-index"
:class="{
'is-active': showYear === pickerYear && quarterIndex === 1,
}"
@click="pickerQuarte(1)"
>第一季度</span
>
<span
class="quarter-index"
:class="{
'is-active': showYear === pickerYear && quarterIndex === 2,
}"
@click="pickerQuarte(2)"
>第二季度</span
>
</div>
<div class="el-quarter__row">
<span
class="quarter-index"
:class="{
'is-active': showYear === pickerYear && quarterIndex === 3,
}"
@click="pickerQuarte(3)"
>第三季度</span
>
<span
class="quarter-index"
:class="{
'is-active': showYear === pickerYear && quarterIndex === 4,
}"
@click="pickerQuarte(4)"
>第四季度</span
>
</div>
</div>
<div class="el-year__content" v-else>
<div class="el-year-item" v-for="item in yearList">
<div
class="cell"
:class="{ 'is-active': showYear == item }"
@click="selectYear(item)">
{{ item }}
</div>
</div>
</div>
</el-popover>
</div>
</template>
<script lang="ts" setup>
import {
DArrowLeft,
DArrowRight,
Close,
Calendar,
} from '@element-plus/icons-vue';
import { computed, onMounted, reactive, ref } from 'vue';
let visible = ref(false);
const props = defineProps({
modelValue: {
type: String,
default: '',
},
});
const emits = defineEmits(['update:modelValue', 'change']);
// 绑定日期
let quarterDate = ref('');
// 选择的年
let pickerYear = ref('') as any;
// 展示的年
let showYear = ref('') as any;
// 选择的季度
let quarterIndex = ref(0);
// 是否展示年份列表
let isEditYear = ref(false);
// 年份列表开始年份
let startYear = ref('') as any;
// 年份列表
let yearList = reactive([] as any);
const quarterTitle = computed(() => {
if (isEditYear.value) {
return startYear.value + '年 - ' + (startYear.value + 9) + '年';
} else {
return showYear.value + '年';
}
});
// 选择某季度
function pickerQuarte(index: number) {
quarterIndex.value = index;
pickerYear.value = showYear.value;
let oldValue = quarterDate.value; // 记录上一次数据
quarterDate.value = pickerYear.value + '-Q' + index;
emits('update:modelValue', quarterDate.value);
// 新老数据不一致,触发change时间
if (oldValue !== quarterDate.value) {
emits('change', quarterDate.value);
}
}
// 更改展示的年
function changeShowYear(num: number) {
if (isEditYear.value) {
startYear.value = startYear.value + num * 10;
// console.log('startYear.value', startYear.value)
changeYearList();
} else {
showYear.value = showYear.value + num;
}
}
// 清空选择的数据
function clearData() {
quarterDate.value = '';
pickerYear.value = '';
showYear.value = new Date().getFullYear();
quarterIndex.value = 0;
}
// 选择的数据
function quarterDateChange(value: any) {
const splitArray = value.split('-Q');
if (splitArray.length < 2) {
pickerYear.value = '';
showYear.value = new Date().getFullYear();
quarterIndex.value = 0;
} else {
pickerYear.value = splitArray[0];
showYear.value = splitArray[0];
quarterIndex.value = splitArray[1];
}
}
// 更改年份列表函数
function changeYearList() {
yearList = [];
let year = startYear.value;
for (let i = 0; i < 10; i++) {
yearList.push(year++);
}
}
// 切换展示年份列表 和 季度
function showYearList() {
if (!isEditYear.value) {
startYear.value = Number(Math.floor(showYear.value / 10) + '0');
changeYearList();
isEditYear.value = true;
} else {
isEditYear.value = false;
}
}
// 选中某个年份列表
function selectYear(item: any) {
showYear.value = item;
isEditYear.value = false;
}
onMounted(() => {
// 初始化展示的年为当前年份
showYear.value = new Date().getFullYear();
startYear.value = Number(Math.floor(showYear.value / 10) + '0');
changeYearList();
});
</script>
<style lang="scss">
.el-quarter__header {
padding-bottom: 12px;
border-bottom: 1px solid #ebeef5;
display: flex;
align-items: center;
justify-content: space-between;
.el-quarter-btn {
font-size: 12px;
}
.el-quarter__header-text {
font-size: 16px;
font-weight: 500;
text-align: center;
cursor: pointer;
}
}
.el-quarter__content {
min-height: 100px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-around;
.el-quarter__row {
display: flex;
justify-content: space-around;
.quarter-index {
display: flex;
padding: 4px 10px;
width: fit-content;
cursor: pointer;
&:hover {
color: #337ecc;
}
}
.is-active {
color: #409eff;
}
}
}
.el-quarter-clear {
position: relative;
color: #909399;
display: none;
height: 12px;
width: 12px;
cursor: pointer;
&::after {
content: '';
position: absolute;
height: 14px;
width: 14px;
margin: auto;
border-radius: 50%;
border: 1px solid #909399;
}
}
.el-input {
&:hover {
.el-quarter-clear {
display: flex;
}
}
}
.el-year__content {
min-height: 100px;
display: flex;
padding: 10px 0;
flex-wrap: wrap;
.el-year-item {
width: calc(100% / 4);
display: flex;
align-items: center;
justify-content: center;
.cell {
padding: 4px 10px;
width: fit-content;
cursor: pointer;
cursor: pointer;
white-space: nowrap;
&:hover {
color: #337ecc;
}
}
.is-active {
color: #409eff;
}
}
}
</style>
二、引用并使用组件
<template>
<div class="app-container">
<el-quarter-picker v-model="value" placeholder="选择季度" />
</div>
</template>
<script setup>
import ElQuarterPicker from './ElQuarterPicker';
</script>