1、DatePicker组件在设置mode=‘year’ disabledDate不生效,不能禁止年单位的选择(新版本才可以!)
2、自己封装了一个,效果(今年为2021年):
3、组件html
<template>
<!-- 年份组件 -->
<div class="yearDate">
<div class="inputBox">
<a-input
v-model="year"
class="yearInput"
@click="showDate"
/>
<a-icon type="calendar" />
</div>
<div class="content">
<div class="chooseBox" ref="listHeight" style="box-shadow: 0 2px 8px rgb(0 0 0 / 15%);" v-show="showList" @mouseleave="handleLeave">
<a-input
ref="modFocus"
v-model="newYear"
class="modInput"
@blur="handleBlur"
/>
<div class="footer">
<div class="btnBox">
<span class="left" @click="handleOld" v-show="isMoreOld">
<a-icon type="double-left" />
</span>
<span class="mid">{{dateSlot}}</span>
<span class="right" @click="handleNow" v-show="isMoreNow">
<a-icon type="double-right" />
</span>
</div>
<div class="listBox">
<ul>
<li v-for="(item, index) in dateShowList" :key="index" @click="edit(item)">
<span :class="{'active': active == index}">{{item.name}}</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'yearDate',
props: ['year'],
data() {
return {
active: 0, // 选中
dateSlot: '', // 显示的年份区间
dateList: { // 所有年份(暂时只做三个区间)
now: [],
old: [],
moreOld: []
},
isMoreOld: true, // 左右箭头显隐
isMoreNow: true,
dateShowList: [], // 展示的年份
showList: false, // 展示年份面板的显隐
newYear: '', // 新的输入框
isSel: false, // 点击选中的
isLeave: false, // 面板鼠标移出
minRange: '', // 中间的年份区间
isBlur: false // 输入框失去焦点
}
},
mounted() {
},
methods: {
// 获取输入的值,用于判断不能超过今年年度
getInputYear(e) {
if(Number(e.target.value) > Number(new Date().getFullYear())) {
// this.newYear = new Date().getFullYear();
this.newYear = this.year;
}
},
// 获取展示的数据
getList() {
// 每次都置空
this.dateList.now = []
this.dateList.old = []
this.dateList.moreOld = []
// 给总年份数据赋值(根据今年的年份往以前的算)
let newYear = new Date().getFullYear()
for(let i = 0; i < 12; i++) {
this.dateList.now.push({
id: i,
name: newYear - (11 - i)
})
this.dateList.old.push({
id: i,
name: newYear - (11*2 + 1 - i)
})
this.dateList.moreOld.push({
id: i,
name: newYear - (11*3 + 2 - i)
})
}
// 因为数据只有三页,所以取中间的年份区间就够了,用于左右箭头的判断
this.minRange = String(this.dateList.old[0].name) + '-' + String(this.dateList.old[11].name)
// 判断处在哪个年份区间
if(newYear >= Number(this.year) && Number(this.year) >= (newYear - 11)) {
this.dateShowList = this.dateList.now
// 左右箭头显隐
this.isMoreNow = false
this.isMoreOld = true
// 过滤,对应的年份样式赋值
this.dateList.now.filter( val => {
if(val.name == Number(this.year)) {
this.active = val.id
}
})
} else if (newYear - 12 >= Number(this.year) && Number(this.year) >= (newYear - 22)) {
this.dateShowList = this.dateList.old
this.isMoreNow = true
this.isMoreOld = true
this.dateList.old.filter( val => {
if(val.name == Number(this.year)) {
this.active = val.id
}
})
} else {
this.dateShowList = this.dateList.moreOld
this.isMoreNow = true
this.isMoreOld = false
this.dateList.moreOld.filter( val => {
if(val.name == Number(this.year)) {
this.active = val.id
}
})
}
// 获取年份区间
this.dateSlot = String(this.dateShowList[0].name) + '-' + String(this.dateShowList[11].name)
},
// 点击右箭头
handleNow() {
// 最新年份没有右箭头,无需判断
if(this.dateSlot == this.minRange) {
// 在中,右往最新
this.dateShowList = this.dateList.now
this.isMoreNow = false
this.isMoreOld = true
} else {
// 不为中,则低,右往中间
this.dateShowList = this.dateList.old
this.isMoreNow = true
this.isMoreOld = true
}
// 年份区间展示
this.dateSlot = String(this.dateShowList[0].name) + '-' + String(this.dateShowList[11].name)
},
// 点击左箭头
handleOld() {
// 最老年份没有左箭头,无需判断
if(this.dateSlot == this.minRange) {
// 在中,左往最老
this.dateShowList = this.dateList.moreOld
this.isMoreNow = true
this.isMoreOld = false
} else {
this.dateShowList = this.dateList.old
this.isMoreNow = true
this.isMoreOld = true
}
// 年份区间展示
this.dateSlot = String(this.dateShowList[0].name) + '-' + String(this.dateShowList[11].name)
},
// 点击旧输入框
showDate() {
this.getList()
this.showList = true
this.newYear = this.year
this.$nextTick(() => {
// 自动获取焦点
this.$refs.modFocus.focus()
// 旧输入框图标隐藏
document.querySelector(".anticon-calendar svg").style.display = 'none'
})
},
// 点击年份
edit(item) {
this.isSel = true
// 输入框失去焦点并且点击了某个年份
if(this.isSel) {
this.active = item.id
this.showList = false
this.$nextTick(() => {
// 传值给父组件
this.$emit('getYear', item.name)
// 旧输入框图标显示
document.querySelector(".anticon-calendar svg").style.display = 'inline-block'
})
}
this.isLeave = false
this.isBlur = false
this.isSel = false
},
// 失去焦点
handleBlur() {
this.isBlur = true
},
// 鼠标移出弹窗
handleLeave() {
this.isLeave = true
// 必须要延迟触发,不然失去焦点没触发到就直接执行了
clearTimeout(timer)
var timer = setTimeout(() => {
if(this.isLeave && this.isBlur) {
// 判断输入框的值
if(this.newYear.length == 4 && Number(this.newYear) < Number(this.year + 1)) {
this.$emit('getYear', this.newYear)
} else {
// 用回默认值
this.$emit('getYear', this.year)
}
// 显示旧输入框
document.querySelector(".anticon-calendar svg").style.display = 'inline-block'
this.showList = false
}
this.isBlur = false
this.isLeave = false
this.isSel = false
}, 500);
},
}
}
</script>
<style lang="less" scoped>
@import "index";
</style>
<style lang="less">
// 年份组件公共样式
.yearDateCommon { // 父组件必须加的类名(防止数据太少,页面高度小于年份组件要展示的高度)
min-height: 64vh;
}
</style>
4、组件样式less
.yearDate {
position: relative;
.inputBox {
position: relative;
/deep/ .anticon-calendar {
position: absolute;
right: 10px;
line-height: 32px;
}
}
.content {
// height: 44px;
.chooseBox {
position: absolute;
top: 0px;
left: 0px;
width: 280px;
font-size: 14px;
line-height: 1.5;
text-align: left;
list-style: none;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #fff;
border-radius: 4px;
outline: none;
-webkit-box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
z-index: 2021;
.modInput {
border: none;
outline: none;
box-shadow: none;
}
.btnBox {
display: flex;
height: 40px;
line-height: 40px;
padding: 0px 10px;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
.left {
width: 20px;
color: rgba(0, 0, 0, 0.45);
cursor: pointer;
}
.mid {
flex: 1;
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
text-align: center;
}
.right {
width: 20px;
color: rgba(0, 0, 0, 0.45);
text-align: right;
cursor: pointer;
}
}
.listBox {
ul {
display: flex;
flex-wrap: wrap;
li {
width: 33.3%;
line-height: 54px;
text-align: center;
span {
display: inline-block;
height: 24px;
margin: 0 auto;
padding: 0 8px;
color: rgba(0, 0, 0, 0.65);
line-height: 24px;
text-align: center;
background: transparent;
border-radius: 2px;
cursor: pointer;
&:hover {
color: #3d9eff;
background: #e6f6ff;
}
}
.active {
color: #fff;
background: #1385ff;
}
}
}
}
}
}
}
/deep/ .anticon-calendar {
color: rgba(0, 0, 0, 0.25);
;
}
5、页面中使用
<template>
<div class="monthCheck yearDateCommon">
<div class="searchBox">
<a-form layout="horizontal" class="searchForm" :form="searchForm">
<div class="inputBox">
<a-form-item label="年度:" class="yearSearch">
<year-date @getYear="getYear" :year="year" />
</a-form-item>
</div>
<div class="btnBox">
<a-button
type="primary"
icon="search"
class="item-btn"
style="background: #108ee9"
@click="handleSearch"
>搜索</a-button
>
<a-button icon="sync" @click="reset"> 重置 </a-button>
</div>
</a-form>
</div>
</div>
</template>
<script>
import yearDate from "@/components/yearDate/index";
export default {
components: {
yearDate
},
data() {
return {
year: new Date().getFullYear(), // 默认当前的年份
};
},
created() {
this.$nextTick(() => {
this.getData();
});
},
methods: {
// 请求表格数据
async getData() {
let year = String(this.year);
this.dataLoad = true;
let res = await this.$http(
this.$url.FAULT_RESPONSE_MONTH_LIST + year,
"get"
);
this.dataLoad = false;
if (res.data.code === 0) {
this.dataSource = res.data.data;
} else {
this.dataSource = [];
}
},
// 获取年份子组件的数据
getYear(data) {
this.year = String(data);
},
}
}
</script>
6、注意两个细节:1是箭头判断和年份区间展示;2是组件展示在父组件中的高度样式(公用类名:yearDateCommon )
广州加油,广东加油,中国加油!