javascript
复制代码
<!--
* @Author: liuyu liuyu@xizhengtech.com
* @Date: 2023-02-01 16:57:27
* @LastEditors: wangping wangping@xizhengtech.com
* @LastEditTime: 2023-06-30 17:25:14
* @Description: 时间选择年 - 年
-->
<template>
<div class="yearPicker" ref="yearPicker" :width="width">
<input class="_inner" :style="bindInputStyle" ref="inputLeft" v-model="startShowYear" @focus="onFocus" @blur="onBlur" type="text" name="yearInput" @keyup="checkStartInput($event)" placeholder="开始年份" />
<span>{{ sp }}</span>
<input class="_inner" :style="bindInputStyle" ref="inputRight" v-model="endShowYear" @focus="onFocus" @blur="onBlur" type="text" name="yearInput" @keyup="checkEndInput($event)" placeholder="结束年份" />
<!-- <i class="dateIcon el-icon-date"></i> 按照自己标准库里面的图标设置-->
<!-- <span class="_inner labelText"></span> -->
<i class="_inner labelText el-icon-date"></i>
<div class="_inner floatPanel" v-if="showPanel">
<div class="_inner leftPanel">
<div class="_inner panelHead">
<i class="_inner el-icon-d-arrow-left" @click="onClickLeft"></i>
{{ leftYearList[0] + " - " + leftYearList[9] }}
</div>
<div class="_inner panelContent">
<div :class="{
oneSelected: item === startYear && oneSelected,
startSelected: item === startYear,
endSelected: item === endYear,
betweenSelected: item > startYear && item < endYear,
}" v-for="item in leftYearList" :key="item">
<a :class="{
cell: true,
_inner: true,
selected: item === startYear || item === endYear,
}" @click="onClickItem(item)" @mouseover="onHoverItem(item)">
{{ item }}
</a>
</div>
</div>
</div>
<div class="line"></div>
<div class="_inner rightPanel">
<div class="_inner panelHead">
<i class="_inner el-icon-d-arrow-right" @click="onClickRight"></i>
{{ rightYearList[0] + " - " + rightYearList[9] }}
</div>
<div class="_inner panelContent">
<div :class="{
startSelected: item === startYear,
endSelected: item === endYear,
betweenSelected: item > startYear && item < endYear,
}" v-for="item in rightYearList" :key="item">
<a :class="{
cell: true,
_inner: true,
selected: item === endYear || item === startYear,
}" @click="onClickItem(item)" @mouseover="onHoverItem(item)">
{{ item }}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from "moment";
const SELECT_STATE = {
unselect: 0,
selecting: 1,
selected: 2,
};
export default {
name: "yearPicker",
computed: {
bindInputStyle() {
return {
"--placeholderColor": "#c0c4cc",
};
},
oneSelected() {
return (
this.curState === SELECT_STATE.selecting &&
(this.startYear === this.endYear || this.endYear == null)
);
},
startDate() {
return this.startYear;
},
leftYearList() {
return this.yearList.slice(0, 10);
},
rightYearList() {
return this.yearList.slice(10, 20);
},
startYearFormat() {
if (this._.isNil(this.startYear)) {
return null;
}
return moment(this.startYear).startOf("year").format("yyyy");
},
endYearFormat() {
if (this._.isNil(this.endYear)) {
return null;
}
return moment(this.endYear).endOf("year").format("yyyy");
},
},
props: {
width: {
default: 200,
},
labelWidth: {
default: 40,
},
sp: {
default: "-",
},
initYear: {
default: null,
},
},
data() {
return {
itemBg: {},
startShowYear: null,
endShowYear: null,
yearList: [],
showPanel: false,
startYear: null,
endYear: null,
curYear: 0,
curSelectedYear: 0,
curState: SELECT_STATE.unselect,
};
},
methods: {
checkStartInput(event) {
if (isNaN(this.startShowYear)) {
this.startShowYear = this.startYear;
} else {
this.startYear = this.startShowYear * 1;
this.changeYear();
}
},
checkEndInput() {
if (isNaN(this.endShowYear)) {
this.endShowYear = this.endYear;
} else {
this.endYear = this.endShowYear * 1;
this.changeYear();
}
},
changeYear() {
if (this.startYear > this.endYear) {
let tmp = this.endYear;
this.endYear = this.startYear;
this.startYear = tmp;
this.startShowYear = this.startYear;
this.endShowYear = this.endYear;
}
if (this.startYear && this.endYear) {
this.$emit("updateTimeRange", {
startYear: moment(this.startYear + "")
.startOf("year")
.valueOf(),
endYear:
moment(this.endYear + "")
.endOf("year")
.valueOf() + 1,
});
} else {
console.warn("WARN:年份不合法", this.startYear, this.endYear);
}
},
onHoverItem(iYear) {
if (this.curState === SELECT_STATE.selecting) {
let tmpStart = this.curSelectedYear;
this.endYear = Math.max(tmpStart, iYear);
this.startYear = Math.min(tmpStart, iYear);
}
},
onClickItem(iYear) {
if (
this.curState === SELECT_STATE.unselect ||
this.curState === SELECT_STATE.selected
) {
this.startYear = iYear;
this.curSelectedYear = iYear;
this.endYear = null;
this.curState = SELECT_STATE.selecting;
} else if (this.curState === SELECT_STATE.selecting) {
this.endShowYear = this.endYear;
this.startShowYear = this.startYear;
this.curState = SELECT_STATE.selected;
this.$emit("updateTimeRange", {
startYear: moment(this.startYear + "")
.startOf("year")
.valueOf(),
endYear:
moment(this.endYear + "")
.endOf("year")
.valueOf() + 1,
});
setTimeout(() => {
//为动画留的时间,可优化
this.showPanel = false;
}, 300);
}
},
onFocus() {
this.$nextTick(() => {
this.showPanel = true;
});
},
onBlur() {
// this.showPanel = false;
},
updateYearList() {
let iStart = Math.floor(this.curYear / 10) * 10 - 10;
iStart = iStart < 0 ? 0 : iStart;
this.yearList = [];
for (let index = 0; index < 20; index++) {
this.yearList.push(iStart + index);
}
},
closePanel(e) {
if (!this.showPanel) {
return;
}
if (typeof e.target.className !== "string") {
this.$nextTick(() => {
this.showPanel = false;
});
return;
}
if (
e.target.className.indexOf("_inner") === -1 ||
(e.target.name === "yearInput" &&
e.target !== this.$refs.inputLeft &&
e.target !== this.$refs.inputRight)
) {
this.$nextTick(() => {
this.showPanel = false;
});
}
e.stopPropagation();
return false;
},
onClickLeft() {
this.curYear = this.curYear * 1 - 10;
this.updateYearList();
},
onClickRight() {
this.curYear = this.curYear * 1 + 10;
this.updateYearList();
},
//------------------对外接口------------------------
//直接传时间戳
setYear(startYearStamp, endYearStamp) {
if (!isNaN(startYearStamp) && !isNaN(endYearStamp)) {
let startYear = moment(startYearStamp).format("yyyy");
let endYear = moment(endYearStamp).format("yyyy");
this.startYear = startYear * 1;
this.endYear = endYear * 1;
this.endShowYear = endYear * 1;
this.startShowYear = startYear * 1;
}
},
},
created() {
this.curYear = moment().format("yyyy");
this.updateYearList();
},
beforeUnmount() {
document.removeEventListener("click", this.closePanel.bind(this));
},
mounted() {
this.$refs.yearPicker.style = "padding-left:" + this.labelWidth + "px";
document.addEventListener("click", this.closePanel.bind(this));
},
};
</script>
<style lang="scss" scoped>
.yearPicker {
font-size: 14px;
display: flex;
position: relative;
transition: all 0.3s;
input {
&::placeholder {
color: var(--placeholderColor); // 动态值
}
}
input:first-child {
text-align: center;
}
.labelText {
position: absolute;
left: 10px;
top: 10px;
color: #c4c6d1;
}
background-color: #fff;
span {
padding: 0 8px;
height: 36px;
line-height: 36px;
}
border: 1px solid #eff1f3;
height: 36px;
line-height: 36px;
border-radius: 4px;
padding: 0 28px 0 8px;
box-sizing: border-box;
.floatPanel {
> div {
width: 50%;
}
// padding: 16px;
position: absolute;
display: flex;
background-color: #fff;
z-index: 9999 !important;
border-radius: 4px;
// width: 650px;
height: 252px;
top: 50px;
left: 0px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border: 1px solid #dfe4ed;
.panelContent {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
// flex-wrap: wrap;
width: 100%;
height: calc(100% - 15px);
margin-top: 8px;
.oneSelected {
border-top-right-radius: 24px;
border-bottom-right-radius: 24px;
}
.startSelected {
background-color: #f2f6fc;
border-top-left-radius: 24px;
border-bottom-left-radius: 24px;
}
.endSelected {
background-color: #f2f6fc;
border-top-right-radius: 24px;
border-bottom-right-radius: 24px;
}
.betweenSelected {
background-color: #f2f6fc;
}
> div {
width: 75px;
height: 48px;
line-height: 48px;
margin: 6px 0;
// border-radius: 24px;
text-align: center;
a {
display: inline-block;
width: 60px;
height: 36px;
cursor: pointer;
line-height: 36px;
border-radius: 18px;
color: #606266;
}
.selected {
background-color: #1890ff;
color: #fff;
}
}
}
.panelHead {
height: 38px;
line-height: 38px;
position: relative;
text-align: center;
font-size: 16px;
border-bottom: 1px solid #dfe4ed;
i {
position: absolute;
cursor: pointer;
&:hover {
color: #1890ff;
}
}
}
.rightPanel {
// padding-left: 8px;
margin: 16px;
display: flex;
flex-direction: column;
}
.line {
width: 1px;
height: 100%;
background: #dfe4ed;
}
.leftPanel {
margin: 16px;
display: flex;
flex-direction: column;
}
.leftPanel .panelHead i {
left: 0px;
top: 10px;
font-size: 14px;
color: #717273;
}
.rightPanel .panelHead i {
right: 0px;
top: 8px;
}
.leftPanel .panelHead i:hover,
.rightPanel .panelHead i:hover {
cursor: pointer;
}
}
.floatPanel::before {
content: "";
border-bottom: 6.5px solid #797979;
border-left: 6.5px solid transparent;
border-right: 6.5px solid transparent;
position: absolute;
left: 44px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
top: -5.5px;
border-radius: 5px;
}
.floatPanel::after {
content: "";
border-bottom: 8px solid #fff;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
position: absolute;
left: 44px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
top: -5px;
border-radius: 5px;
}
}
input {
width: 100px;
border: none;
height: 37px;
line-height: 37px;
box-sizing: border-box;
background-color: transparent;
text-align: center;
color: #606266;
}
input:focus {
outline: none;
background-color: transparent;
}
.yearPicker:hover {
border-color: #1890ff;
}
.dateIcon {
position: absolute;
right: 16px;
top: 9px;
color: #adb2bc;
}
</style>