elementUI 不支持年份范围的选择器,依照下面的文章进行修改和完善 el-year-picker;
element日期选择范围、选择年份范围_elemet 两个日期 选择的年份范围必须在三年之内-CSDN博客
el-year-picker 组件:
依赖包:moment
属性:
- sp:默认 ‘至’
- value:默认 [ ]
- size:默认 large,支持 small、mini
- clearable:默认 true
- startPlaceholder:默认 开始年份
-
endPlaceholder:默认 结束年份
事件:
- input:参数 value[ ]
效果图
代码
index.vue
<template><el-popoverref="popover"placement="bottom"v-model="showPanel"popper-class="custom_year_range"trigger="manual"v-clickoutside="() => { showPanel = false }"><div class="_inner floatPanel"><div class="_inner leftPanel"><div class="_inner panelHead"><i class="_inner el-icon-d-arrow-left" @click="onClickLeft"></i><span>{{ leftYearList[0] + '年 ' + '- ' + leftYearList[9] + '年' }}</span></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="_inner rightPanel"><div class="_inner panelHead"><i class="_inner el-icon-d-arrow-right" @click="onClickRight"></i><span>{{ rightYearList[0] + '年 ' + '- ' + rightYearList[9] + '年' }}</span></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 slot="reference"><divref="yearPicker"style="width: 100%"class="el-date-editor el-range-editor el-input__inner el-date-editor--daterange yearPicker":class="['el-range-editor--' + size, showPanel ? 'is-active' : '', startShowYear ? 'is-val' : '']"@mouseover="handleHover(true)"@mouseleave="handleHover(false)"><i class="el-input__icon el-range__icon el-icon-date"></i><inputclass="_inner range_input"ref="inputLeft"type="text"name="yearInput":placeholder="startPlaceholder"v-model="startShowYear"@focus="onFocus"@keyup="handleInput('start')"/><span class="el-range-separator">{{ sp }}</span><inputclass="_inner range_input"ref="inputRight"type="text"name="yearInput":placeholder="endPlaceholder"v-model="endShowYear"@focus="onFocus"@keyup="handleInput('end')"/><iclass="el-input__icon el-range__close-icon":class="[startShowYear && isHover && clearable ? 'el-icon-circle-close' : '']"@click="onClear"></i></div></div></el-popover>
</template><script>
import moment from 'moment'
import { clickoutside, SELECT_STATE } from './utils.js'
export default {name: 'ElYearPicker',directives: { clickoutside },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)}},props: {sp: {default: '至'},value: {type: Array,default: [],},size: {type: String,default: 'large'},clearable: {type: Boolean,default: true},startPlaceholder: {type: String,default: '开始年份'},endPlaceholder: {type: String,default: '结束年份'}},data () {return {itemBg: {},startShowYear: null,endShowYear: null,yearList: [],showPanel: false,startYear: null,endYear: null,curYear: 0,curSelectedYear: 0,curState: SELECT_STATE.unselect,isHover: false}},methods: {handleInput (type) {switch (type) {case 'start':if (isNaN(this.startShowYear)) {this.startShowYear = this.startYearreturn}this.startYear = this.startShowYear * 1breakcase 'end':if (isNaN(this.endShowYear)) {this.endShowYear = this.endYearreturn}this.endYear = this.endShowYear * 1break}[this.startYear, this.endYear] = [this.endYear, this.startYear]this.startShowYear = this.startYearthis.endShowYear = this.endYear},onHoverItem (iYear) {if (this.curState === SELECT_STATE.selecting) {const tmpStart = this.curSelectedYearthis.endYear = Math.max(tmpStart, iYear)this.startYear = Math.min(tmpStart, iYear)}},async onClickItem (selectYear) {if (this.curState === SELECT_STATE.unselect ||this.curState === SELECT_STATE.selected) {this.startYear = selectYearthis.curSelectedYear = selectYearthis.endYear = nullthis.curState = SELECT_STATE.selecting} else if (this.curState === SELECT_STATE.selecting) {this.endShowYear = this.endYear || this.startYearthis.startShowYear = this.startYearthis.curState = SELECT_STATE.selectedawait this.$nextTick()this.showPanel = falsethis.$parent.$parent.$parent.$parent.$parent.clearValidate()}},async onFocus () {await this.$nextTick()this.showPanel = true},handleHover (flag) {this.isHover = flag},updateYearList () {const startYear = ~~(this.curYear / 10) * 10console.log(startYear, this.curYear, 'this.curYearthis.curYearthis.curYear')this.yearList = []for (let index = 0; index < 20; index++) {this.yearList.push(startYear + index)}},onClickLeft () {this.curYear = this.curYear * 1 - 10this.updateYearList()},onClickRight () {this.curYear = this.curYear * 1 + 10this.updateYearList()},onClear () {if (this.startShowYear && this.isHover && this.clearable) {this.startYear = nullthis.endYear = nullthis.curSelectedYear = 0this.curState = SELECT_STATE.unselectthis.showPanel = false;this.curYear = moment().format('yyyy')this.updateYearList()this.startShowYear = ''this.endShowYear = ''this.$emit('input', [])}}},watch: {value: {handler (val) {if (val.length == 0) {this.startShowYear = ''this.endShowYear = ''} else {const [first, end] = val || []this.startShowYear = val[0]this.endShowYear = val[1]}},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 () {console.log('value', this.value)const [startYear, endYear] = this.value || []if (startYear) {this.startYear = Number(startYear)this.endYear = Number(endYear)this.curState = SELECT_STATE.selectedthis.curYear = startYear} else {this.curYear = moment().format('yyyy')}this.updateYearList()},mounted () {window.Vue = this}
}
</script>
<style lang="scss">
.custom_year_range {border-radius: 10px;.floatPanel {> div {width: 50%;}padding: 0 16px;// position: absolute;display: flex;background-color: #fff;z-index: 2000;border-radius: 4px;width: 650px;height: 250px;top: 40px;left: -50px;.panelContent {display: flex;flex-wrap: wrap;width: 100%;height: calc(100% - 70px);.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: 3px 0;// border-radius: 24px;text-align: center;a {display: inline-block;width: 60px;height: 36px;cursor: pointer;line-height: 36px;border-radius: 18px;&:hover {color: #409eff;}}.selected {background-color: #409eff;color: #fff;&:hover {color: #fff !important;}}}}.panelHead {position: relative;height: 46px;line-height: 46px;text-align: center;display: flex;align-items: center;justify-content: center;span {font-size: 16px;font-weight: 500;padding: 0 5px;line-height: 22px;text-align: center;cursor: pointer;color: #606266;&:hover {color: #409eff;}}i {position: absolute;cursor: pointer;&:hover {color: #3e77fc;}}}.rightPanel {padding-left: 8px;}.leftPanel .panelHead i {left: 20px;}.rightPanel .panelHead i {right: 20px;}}.floatPanel::before {content: '';height: 100%;top: 0;position: absolute;left: 50%;width: 1px;border-left: 1px solid #e4e4e4;}.cell._inner {color: #606266;text-decoration: none;}
}
</style>
<style lang="scss" scoped>
.range_input {appearance: none;border: none;outline: 0;padding: 0;width: 130px;color: #606266;line-height: 1;height: 100%;margin: 0;text-align: center;display: inline-block;
}.yearPicker {.el-icon-circle-close {color: #c0c4cc;&:hover {color: #909399;}}&.is-val {}&.is-active {border-color: #0052d9 !important;}
}input {width: 60px;border: none;height: 32px;line-height: 32px;box-sizing: border-box;background-color: transparent;
}input:focus {outline: none;background-color: transparent;
}
.dateIcon {position: absolute;right: 16px;top: 9px;color: #adb2bc;
}
</style>
utils.js
export const clickoutside = {bind(el, binding, vnode) {function documentHandler(e) {// 这里判断点击的元素是否是本身,是本身,则返回if (el.contains(e.target)) {return false}// 判断指令中是否绑定了函数if (binding && binding.expression) {// 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法if (binding.value && binding.value(e)) {binding.value(e)}}}// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听el.__vueClickOutside__ = documentHandlerdocument.addEventListener('click', documentHandler)},unbind(el, binding) {// 解除事件监听document.removeEventListener('click', el.__vueClickOutside__)delete el.__vueClickOutside__}
}export const SELECT_STATE = {unselect: 0,selecting: 1,selected: 2
}