一. 前言
众所周知,前端童靴们在日常开发中,不管是使用 Element 还是Iview 的组件库过程中,遇到季度选择器或者是上下半年度选择器的需求的时候,都会陷入思索---该如何开发呢?因为世面上的大多组件库都未提供季度选择或者是上下半年度选择(PS:Arco Design 倒是提供了季度选择器,可是适配Vue3,不兼容Vue2)。所以本文就以上两种选择器提供一种实现方案(附:组件源码),后续也会将它们封装成拿来即用的轮子,方便大家使用。
二. 季度选择器
- 效果图:
- 组件源代码:
<template>
<div>
<!--背景-点击可关闭卡片-->
<mark
class="bgCard"
v-if="showQuarter"
@click.stop="showQuarter = false"
></mark>
<span>
<el-input
v-model="choseQuarter"
prefix-icon="el-icon-date"
:clearable="false"
placeholder="请选择季度"
@clear="clearClick"
@focus="focusClick"
/>
</span>
<div v-show="showQuarter" class="show1">
<p>
<button
type="button"
aria-label="前一年"
class="
el-picker-panel__icon-btn
el-date-picker__prev-btn
el-icon-d-arrow-left
"
@click="prev"
/>
<span role="button" class="span-year">{{ year }}年</span>
<button
type="button"
aria-label="后一年"
class="
el-picker-panel__icon-btn
el-date-picker__next-btn
el-icon-d-arrow-right
"
@click="next"
/>
</p>
<div>
<span
v-for="(item, index) in fullMonth"
:key="index"
:class="[
'selectMonth',
choseQuarter.split('-')[1] === item ? 'is-active' : '',
]"
@click="selectQuarter(item)"
>{{ item }}</span
>
</div>
</div>
</div>
</template>
<script>
export default {
name: "quarterzj",
props: {
searchQuarter: {
type: String,
default: ''
}
},
data() {
return {
showQuarter: false, //显隐该季度组件
year: new Date().getFullYear(),
fullMonth: ["第一季度", "第二季度", "第三季度", "第四季度"],
choseQuarter: new Date().getFullYear().toString() + "-" + "第一季度", //input双向绑定的内容
};
},
watch: {
//为了展开组件时人性化对上现有年份或者是还原当前年份
showQuarter(bool) {
if (bool) {
if (this.choseQuarter) {
this.year = this.choseQuarter.split("-")[0];
} else {
this.year = new Date().getFullYear().toString();
}
}
},
//父组件还原检索清空时同步给季度组件
searchQuarter(val){
console.log('val',val);
if(val){
this.choseQuarter = val;
}else{
this.choseQuarter = new Date().getFullYear().toString() + "-" + "第一季度";
}
}
},
methods: {
// 点击季度按钮
quarterTime() {
this.choseQuarter = "";
this.fullMonth = ["第一季度", "第二季度", "第三季度", "第四季度"];
},
// input框聚焦
focusClick() {
this.showQuarter = true;
},
// 上一年
prev() {
this.year = this.year * 1 - 1;
},
// 下一年
next() {
this.year = this.year * 1 + 1;
},
//清空
clearClick() {
this.choseQuarter = "";
this.showQuarter = false;
this.$emit("getYearValue", this.choseQuarter);
},
// 点击选项事件
selectQuarter(item) {
switch (item) {
case "第一季度":
this.choseQuarter = this.year + "-" + "第一季度";
break;
case "第二季度":
this.choseQuarter = this.year + "-" + "第二季度";
break;
case "第三季度":
this.choseQuarter = this.year + "-" + "第三季度";
break;
case "第四季度":
this.choseQuarter = this.year + "-" + "第四季度";
break;
default:
this.choseQuarter = "";
}
this.showQuarter = false;
this.$emit("getYearValue", this.choseQuarter);
},
},
};
</script>
<style lang="less" scoped>
.bgCard {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
z-index: 999;
}
.show1 {
width: 320px;
margin-top: 5px;
position: absolute;
z-index: 999;
height: auto;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
background: #fff;
padding: 5px;
font-size: 14px;
color: #606266;
}
.show1 p:nth-child(1) {
width: 100%;
height: 40px;
border-bottom: 1px solid #f5f5f5;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 10px;
}
.show1 > div {
width: 100%;
height: auto;
}
.show1 > div span {
width: 50%;
}
.selectMonth {
display: inline-block;
float: left;
width: 78px;
height: 40px;
line-height: 40px;
text-align: center;
}
.selectMonth:hover {
background: rgba(19, 131, 255, 0.052);
}
.span-year {
width: 90%;
margin: 0 auto;
display: inline-block;
text-align: center;
line-height: 40px;
}
.is-active {
color: #02bca5 !important;
border: hidden;
}
</style>
- 组件引入使用:
三 .上下半年度选择器
- 效果图:
- 组件源代码:
<template>
<div>
<!--背景-点击可关闭卡片-->
<mark
class="bgCard"
v-if="showSeason"
@click.stop="showSeason = false"
></mark>
<el-input
placeholder="请选择上下半年度"
v-model="showValue"
style="width: 200px"
:clearable="false"
@clear="clearClick"
@focus="focusClick"
>
<i slot="prefix" class="el-input__icon el-icon-date"></i>
</el-input>
<!-- 上下半年选择器卡片 -->
<el-collapse-transition>
<el-card class="box-card" v-if="showSeason">
<!-- 年份选择器 -->
<div
slot="header"
class="clearfix"
style="text-align: center; padding: 0"
>
<button
type="button"
aria-label="前一年"
class="
el-picker-panel__icon-btn
el-date-picker__prev-btn
el-icon-d-arrow-left
"
@click="prevSub"
></button>
<span role="button" class="el-date-picker__header-label"
>{{ year }}年</span
>
<button
type="button"
aria-label="后一年"
@click="nextAdd"
class="
el-picker-panel__icon-btn
el-date-picker__next-btn
el-icon-d-arrow-right
"
></button>
</div>
<!-- 上下半年选择器 -->
<div class="quarter-block">
<div class="text-item">
<el-button
type="text"
size="medium"
:class="[
'common-quarter',
'quarter-one',
showValue.split('-')[1] === '上半年' ? 'is-active' : '',
]"
@click="selectQuarter('上半年')"
>上半年</el-button
>
<el-button
type="text"
size="medium"
:class="[
'common-quarter',
'quarter-two',
showValue.split('-')[1] === '下半年' ? 'is-active' : '',
]"
@click="selectQuarter('下半年')"
>下半年</el-button
>
</div>
</div>
</el-card>
</el-collapse-transition>
</div>
</template>
<script>
export default {
name: "yearzj",
props: {
searchYear: {
type: String,
default: ''
}
},
data() {
return {
showSeason: false, //组件显隐
year: new Date().getFullYear(), //默认当前年
showValue: new Date().getFullYear().toString() + "-" + '上半年', //input双向绑定的内容
rules: {
showValue: [{ required: true, message: "不能为空", trigger: "change" }],
},
};
},
watch: {
//为了展开组件时人性化对上现有年份或者是还原当前年份
showSeason(bool){
if(bool){
if(this.showValue){
this.year = this.showValue.split('-')[0];
}else{
this.year = new Date().getFullYear().toString();
}
}
},
//父组件还原检索清空时同步给上下半年度组件
searchYear(val){
if(val){
this.showValue = val;
}else{
this.showValue = new Date().getFullYear().toString() + "-" + '上半年';
}
}
},
methods: {
// 上一年
prevSub() {
this.year = this.year * 1 - 1;
},
// 下一年
nextAdd() {
this.year = this.year * 1 + 1;
},
// 上下半年选择
selectQuarter(quarter) {
this.showValue = `${this.year}-${quarter}`;
this.$emit("getQuarterValue", this.showValue);
this.showSeason = false;
},
// 清除
clearClick() {
this.showValue = "";
this.$emit("getQuarterValue", this.showValue);
this.showSeason = false;
},
// 聚焦触发,若是年已存在,则不需要重新赋值
focusClick() {
if (!this.year) {
this.year = new Date().getFullYear().toString();
}
this.showSeason = true;
},
},
created() {
this.showValue = this.searchYear;
},
};
</script>
<style lang="less" scoped>
.bgCard {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
z-index: 999;
}
.box-card {
width: 220px;
padding: 0 3px 0px;
margin-top: 10px;
position: fixed;
z-index: 9999;
}
.common-quarter {
width: 40%;
color: #606266;
}
.quarter-one,
.quarter-three {
float: left;
}
.quarter-two,
.quarter-four {
float: right;
}
.text-item {
text-align: center;
}
.quarter-block {
display: flex;
flex-direction: column;
}
.is-active {
color: #02bca5 !important;
border: hidden;
}
</style>
- 组件引入使用: