element ui 年份范围选择器封装
element 组件库 关于月份范围 以及 日期范围选择器都有相对应的组件 但是年份范围选择器没有给到 因为公司业务需要 我就根据饿了么组件以及其他程序⚪的代码封装了一个年份范围选择器
- 先看组件效果
相关代码
<template>
<div class="year-all">
<transition name="el-zoom-in-top">
<div
v-show="showPanel"
ref="popover"
class="el-popover"
placement="bottom"
popper-class="custom_year_range"
trigger="manual"
>
<div class="_inner float-panel">
<div class="_inner left-panel">
<div class="_inner panel-head">
<i
class="_inner el-icon-d-arrow-left"
@click="onClickLeft"
></i>
<span class="year-main">
{{ leftYearList[0] + '年 ' + '- ' + leftYearList[9] + '年' }}
</span>
</div>
<div class="_inner panel-content">
<div
v-for="item in leftYearList"
:key="item"
class="year-item"
:class="{
oneSelected: item === startYear && oneSelected,
startSelected: item === startYear,
endSelected: item === endYear,
betweenSelected: item > startYear && item < endYear,
}"
@click="onClickItem(item)"
@mouseover="onHoverItem(item)"
>
<a
:class="{
cell: true,
_inner: true,
selected: item === startYear || item === endYear,
}"
>
{{ item }}
</a>
</div>
</div>
</div>
<div class="_inner right-panel">
<div class="_inner panel-head">
<i
class="_inner el-icon-d-arrow-right"
@click="onClickRight"
></i>
<span class="year-main">{{ rightYearList[0] + '年 ' + '- ' + rightYearList[9] + '年' }}</span>
</div>
<div class="_inner panel-content">
<div
v-for="item in rightYearList"
:key="item"
class="year-item"
:class="{
startSelected: item === startYear,
endSelected: item === endYear,
betweenSelected: item > startYear && item < endYear,
}"
>
<a
:class="{
cell: true,
_inner: true,
selected: item === endYear || item === startYear,
}"
@click="onClickItem(item)"
@mouseover="onHoverItem(item)"
>
{{ item }}
</a>
</div>
</div>
</div>
</div>
</div>
</transition>
<div slot="reference">
<div
ref="yearPicker"
style="width: 100%"
class="el-date-editor el-range-editor el-input__inner el-date-editor--daterange el-range-editor--small"
@mouseover="onHoverIcon"
@mouseleave="lossHoverIcon"
>
<img
src="@/assets/image/common/icon_date.png"
class="el-icon-date"
@click="clickLeftIcon"
>
<input
ref="inputLeft"
v-model="startShowYear"
class="_inner range_input"
type="text"
name="yearInput"
placeholder="开始年份"
readonly="readonly"
@focus="onFocus"
@keyup="handleInput('start')"
/>
<span class="el-range-separator">{{ sp }}</span>
<input
ref="inputRight"
v-model="endShowYear"
readonly="readonly"
class="_inner range_input"
type="text"
name="yearInput"
placeholder="结束年份"
@focus="onFocus"
@keyup="handleInput('end')"
/>
<!-- 删除icon -->
<i
v-show="isClearIconShow"
class="el-input__icon el-range__close-icon el-icon-circle-close"
@click="clearSelectYear"
></i>
</div>
</div>
</div>
</template>
<script>
import DayJs from 'dayjs'
import { SELECT_STATE } from '@/utils/index.js'
export default {
name: 'YearPicker',
props: {
sp: {
type: String,
default: '至'
},
value: {
type: Object,
default: null
}
},
data() {
return {
isClearIconShow: false,
itemBg: {},
startShowYear: null,
endShowYear: null,
yearList: [],
showPanel: false,
startYear: null,
endYear: null,
curYear: 0,
curSelectedYear: 0,
curState: SELECT_STATE.unselect,
isDisplay: false
}
},
computed: {
oneSelected() {
return this.curState === SELECT_STATE.selecting && (this.startYear === this.endYear || this.endYear == null)
},
leftYearList() {
return this.yearList.slice(0, 10)
},
rightYearList() {
return this.yearList.slice(10, 20)
}
},
watch: {
value: {
handler(val) {
if (val?.length === 0) return
const [first, end] = val || []
this.startShowYear = first
this.endShowYear = end
},
immediate: true,
deep: true
},
startShowYear: {
handler(val) {
this.$emit('input', [val, this.endShowYear || ''])
},
immediate: true,
deep: true
},
endShowYear: {
handler(val) {
this.$emit('input', [this.startShowYear || '', val])
},
immediate: true,
deep: true
}
},
created() {
const [startYear, endYear] = this.value || []
if (startYear) {
this.startYear = Number(startYear)
this.endYear = Number(endYear)
this.curState = SELECT_STATE.selected
this.curYear = startYear
} else {
this.curYear = DayJs().year()
}
this.updateYearList()
},
mounted() {
window.Vue = this
},
methods: {
clickLeftIcon() {
this.showPanel = true
},
clearSelectYear() {
this.startShowYear = undefined
this.endShowYear = undefined
this.startYear = ''
this.endYear = ''
},
handleInput(type) {
switch (type) {
case 'start':
if (isNaN(this.startShowYear)) {
this.startShowYear = this.startYear
return
}
this.startYear = this.startShowYear * 1
break
case 'end':
if (isNaN(this.endShowYear)) {
this.endShowYear = this.endYear
return
}
this.endYear = this.endShowYear * 1
break
}
[this.startYear, this.endYear] = [this.endYear, this.startYear]
this.startShowYear = this.startYear
this.endShowYear = this.endYear
},
onHoverItem(iYear) {
if (this.curState === SELECT_STATE.selecting) {
const tmpStart = this.curSelectedYear
this.endYear = Math.max(tmpStart, iYear)
this.startYear = Math.min(tmpStart, iYear)
}
},
onHoverIcon() {
if (this.startShowYear !== undefined && this.endShowYear !== undefined) {
this.isClearIconShow = true
} else {
this.isClearIconShow = false
}
},
lossHoverIcon() {
this.isClearIconShow = false
},
async onClickItem(selectYear) {
if (
this.curState === SELECT_STATE.unselect ||
this.curState === SELECT_STATE.selected
) {
this.startYear = selectYear
this.curSelectedYear = selectYear
this.endYear = null
this.curState = SELECT_STATE.selecting
} else if (this.curState === SELECT_STATE.selecting) {
this.endShowYear = this.endYear || this.startYear
this.startShowYear = this.startYear
this.curState = SELECT_STATE.selected
await this.$nextTick()
this.showPanel = false
}
},
async onFocus() {
await this.$nextTick()
this.showPanel = true
},
updateYearList() {
const startYear = ~~(this.curYear / 10) * 10
this.yearList = []
for (let index = 0; index < 20; index++) {
this.yearList.push(startYear + index)
}
},
onClickLeft() {
this.curYear = this.curYear * 1 - 10
this.updateYearList()
},
onClickRight() {
this.curYear = this.curYear * 1 + 10
this.updateYearList()
}
}
}
</script>
<style lang="scss" scoped>
.year-all {
position: relative;
.el-popover {
width: 644px;
height: 250px;
top: 44px;
.float-panel {
position: relative;
display: flex;
justify-content: space-between;
.left-panel,
.right-panel {
width: 50%;
padding: 0 16px;
.panel-head {
font-size: 16px;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
.year-main {
display: flex;
}
.year-main:hover {
color: #2F45FF;
cursor: pointer;
}
}
.panel-content {
font-size: 14px;
display: flex;
justify-self: start;
flex-wrap: wrap;
.year-item {
display: flex;
justify-content: center;
align-items: center;
width: 64px;
height: 32px;
margin-bottom: 12px;
margin-right: 4px;
}
.year-item:hover {
cursor: pointer;
background: #F4F4F7;
border-radius: 2px;
color: #333;
}
.startSelected {
background: #fff !important;
border: 1px solid #2F45FF;
border-radius: 2px;
color: #2F45FF;
}
.endSelected {
background: #fff !important;
border: 1px solid #2F45FF;
border-radius: 2px;
color: #2F45FF;
}
.year-item:active {
background: #fff;
border: 1px solid #2F45FF;
border-radius: 2px;
}
}
}
.left-panel {
border-right: 1px solid #ebeef5;
}
.el-icon-d-arrow-right {
position: absolute;
right: 0;
}
.el-icon-d-arrow-right:hover {
color: #2F45FF;
cursor: pointer;
}
.el-icon-d-arrow-left {
position: absolute;
left: 0;
}
.el-icon-d-arrow-left:hover {
color: #2F45FF;
cursor: pointer;
}
}
}
.el-icon-date {
width: 18px;
height: 18px;
}
.el-icon-date:hover {
cursor: pointer;
}
.el-range__close-icon {
display: flex;
align-items: center;
}
.range_input {
appearance: none;
border: none;
outline: 0;
padding: 0;
width: 86px;
color: #606266;
line-height: 40px;
height: 40px;
margin: 0;
text-align: center;
color: #646566;
font-size: 14px;
}
.yearPicker {
input:first-child {
text-align: right;
}
.labelText {
position: absolute;
left: 8px;
}
background-color: #fff;
span {
padding: 0 8px;
height: 32px;
line-height: 32px;
}
border: 1px solid #eff1f3;
height: 34px;
line-height: 34px;
border-radius: 4px;
padding: 0 28px 0 8px;
box-sizing: border-box;
}
input {
width: 60px;
border: none;
height: 32px;
line-height: 32px;
box-sizing: border-box;
background-color: transparent;
}
input:focus {
outline: none;
background-color: transparent;
}
.yearPicker:hover {
border-color: #3e77fc;
}
.dateIcon {
position: absolute;
right: 16px;
top: 9px;
color: #adb2bc;
}
}
</style>
使用方式