效果图
组件代码
html代码
<template>
<div class="dateTemplate">
<div class="time">
<div v-for="(item,index) in dateList" :key="index" :class="{ istime: activedTimeDate == index }" @click="activedTime(index,item)" v-show="(item.name!='自定义')">
{{ item.name }}
</div>
<div @click="activedTime(dateList.length-1,dateList[dateList.length-1])" v-show="(dateList[dateList.length-1].name=='自定义')">
<div v-if="isdata">
{{ dateList[dateList.length-1].name }}
<img width="6" height="4" src="@/assets/images/sanjiao.png" />
</div>
<div :class="{ istime: activedTimeDate == dateList.length-1 }" v-else class="dataBox">
<p>{{ startDate }}</p>
<p>{{ endDate }}</p>
<img width="6" height="4" src="@/assets/images/redsanjiao.png" alt="" />
</div>
</div>
</div>
<div class="date" v-if="show">
<div class="xuanze" @click="clickData">
<div class="left" :class="{ actived: isActived }" @click="actived(0)">
{{ startDate }}
</div>
<span>至</span>
<div class="left right" :class="{ actived: !isActived }" @click="actived(1)">
{{ endDate }}
</div>
</div>
<van-datetime-picker v-model="currentDate" type="date" title="日期筛选" :max-date="maxDate" :min-date="minDate" :formatter="formatter" @change="change" @cancel="cancel" @confirm="confirm"></van-datetime-picker>
</div>
<van-overlay :show="show" @click="overlay"></van-overlay>
<div class="overlayimg" v-show="showoverlay">
<img width="55" height="55" src="@/assets/images/tanhao1.png" alt="" />
<p>无效的日期</p>
</div>
</div>
</template>
js代码
//自己定义的接口(ts语法)
// import { DateListPop } from '@/models/simulationMargin';
import { PropType } from 'vue/types/v3-component-props';
export interface DateListPop {
value: number;
type: string;
name:string
}
<script lang="ts">
export default {
name: 'DateTemplate',
components: {},
data() {
return {
minDate: '' as string,
maxDate: '' as string,
currentDate: '' as string,
isActived: true as boolean,
startDate: '' as string,
endDate: '' as string,
isActivedNumber: 0 as number,
active: 1 as number,
istime: true as boolean,
activedTimeDate: 0 as number,
show: false as boolean,
showoverlay: false as boolean,
isdata: true as boolean,
getTime: '' as string
};
},
props: {
// type:day 天 month 月 year 年 custom 自定义
dateList: {
type: Array as PropType<DateListPop[]>,
default: () => [
{ value: 3, type: 'day', name: '近三天' },
{ value: 7, type: 'day', name: '近一周' },
{ value: 1, type: 'month', name: '近一月' },
// { value: 1, type: 'year', name: '近一年' },
{ value: 0, type: 'custom', name: '自定义' }
]
},
initDate: {
type: Object,
default: () => ({ value: 1, type: 'year' })
},
minDatePop: {
type: Object,
default: () => ({ value: 3, type: 'year' })
},
maxDatePop: {
type: Object,
default: () => ({ value: 0, type: 'year' })
}
},
mounted() {
this.get5();
},
methods: {
// 获取时间
get5() {
this.getTime = new Date();
if (this.maxDatePop.type == 'year') {
this.maxDate = new Date(this.getRecentYear_Date(this.maxDatePop.value).split(' ')[0]);
} else if (this.maxDatePop.type == 'month') {
this.maxDate = new Date(this.getRecentMonth_Date(this.maxDatePop.value).split(' ')[0]);
} else if (this.maxDatePop.type == 'day') {
this.maxDate = new Date(this.getRecentDay_Date(this.maxDatePop.value).split(' ')[0]);
}
if (this.minDatePop.type == 'year') {
this.minDate = new Date(this.getRecentYear_Date(this.minDatePop.value).split(' ')[0]);
} else if (this.minDatePop.type == 'month') {
this.minDate = new Date(this.getRecentMonth_Date(this.minDatePop.value).split(' ')[0]);
} else if (this.minDatePop.type == 'day') {
this.minDate = new Date(this.getRecentDay_Date(this.minDatePop.value).split(' ')[0]);
}
this.currentDate = new Date();
this.activedTime(0, this.dateList[0]);
});
},
overlay() {
this.show = false;
this.showoverlay = false;
},
// 时间转换成yy-mm-dd
getYYMMDD(val: any) {
const time = val;
const year = time.getFullYear().toString().padStart(4, '0');
const mon = (time.getMonth() + 1).toString().padStart(2, '0');
const day = time.getDate().toString().padStart(2, '0');
const curTime = year + '-' + mon + '-' + day;
return curTime;
},
formatter(type: string, val: any) {
if (type === 'year') {
return `${val}年`;
} else if (type === 'month') {
return `${val}月`;
} else if (type === 'day') {
return `${val}日`;
}
return val;
},
cancel() {
this.show = false;
this.showoverlay = false;
},
confirm() {
if (new Date(this.startDate) > new Date(this.endDate)) {
this.show = true;
this.showoverlay = true;
setTimeout(() => {
this.showoverlay = false;
}, 1.5 * 1000);
} else {
this.cancel();
this.$emit('activedTime', {
startDate: this.startDate,
endDate: this.endDate
});
this.isdata = false;
}
},
/**
*获取近n天的日期
*{param:number } dayNum 天数
*/
getRecentDay_Date(dayNum: number) {
let result = '';
const dd = new Date(this.getTime.getTime() - 3600 * 1000 * 24 * dayNum);
const y = dd.getFullYear();
const m = (dd.getMonth() + 1).toString().padStart(2, '0'); //获取当前月份的日期
const d = dd.getDate().toString().padStart(2, '0');
const day = y + '-' + m + '-' + d;
const curTime = this.getYYMMDD(this.getTime);
result += day + ' ';
result += curTime;
return result;
},
/**
*获取近n月的日期
*{param:number } monthNum 月数
*/
getRecentMonth_Date(monthNum: number) {
let result = '';
let datenow = this.getTime;
const dateend = datenow.getFullYear().toString() + '-' + (datenow.getMonth() + 1).toString().padStart(2, '0') + '-' + datenow.getDate().toString().padStart(2, '0');
const dateArr = dateend.split('-');
const year: any = dateArr[0]; //获取当前日期的年份
const month: any = dateArr[1]; //获取当前日期的月份
const day: any = dateArr[2]; //获取当前日期的日
let days: any = new Date(year, month, 0);
days = days.getDate(); //获取当前日期中月的天数
let year2 = year;
let month2: any = parseInt(month) - monthNum;
if (month2 <= 0) {
var absM: any = Math.abs(month2);
year2 = parseInt(year2) - Math.ceil(absM / 12 == 0 ? 1 : parseInt(absM) / 12);
month2 = 12 - (absM % 12);
}
let day2 = day;
let days2: any = new Date(year2, month2, 0);
days2 = days2.getDate();
if (day2 > days2) {
day2 = days2;
}
if (month2 < 10) {
month2 = '0' + month2;
}
var t2 = year2 + '-' + month2.toString().padStart(2, '0') + '-' + day2.toString().padStart(2, '0');
result += t2 + ' ';
result += dateend;
return result;
},
/**
*获取近n年的日期
*{param:number } yearNum 年数
*/
getRecentYear_Date(yearNum: number) {
let result = '';
const dd = new Date(this.getTime);
dd.setFullYear(dd.getFullYear() - yearNum);
const y = dd.getFullYear();
const m = (dd.getMonth() + 1).toString().padStart(2, '0');
const d = dd.getDate().toString().padStart(2, '0');
const curTime = this.getYYMMDD(this.getTime);
const day = y + '-' + m + '-' + d;
result += day + ' ';
result += curTime;
return result;
},
activedTime(val: number, item?: any) {
console.log(val, item, item == undefined, 'val=======点击');
this.activedTimeDate = val;
this.isdata = true;
this.show = false;
let dateval = [];
// type:day 天 month 月 year 年 custom 自定义
if (item.type == 'day') {
dateval = this.getRecentDay_Date(item.value).split(' ');
} else if (item.type == 'month') {
dateval = this.getRecentMonth_Date(item.value).split(' ');
} else if (item.type == 'year') {
dateval = this.getRecentYear_Date(item.value).split(' ');
} else if (item.type == 'custom') {
this.show = true;
//自定义时间默认显示一年
if (this.initDate.type == 'year') {
dateval = this.getRecentYear_Date(this.initDate.value).split(' ');
} else if (this.initDate.type == 'month') {
dateval = this.getRecentMonth_Date(this.initDate.value).split(' ');
} else if (this.initDate.type == 'day') {
dateval = this.getRecentDay_Date(this.initDate.value).split(' ');
}
if (this.isActivedNumber == 0) {
this.currentDate = new Date(dateval[0]);
} else {
this.currentDate = new Date(dateval[1]);
}
}
this.startDate = dateval[0];
this.endDate = dateval[1];
if (item.type != 'custom') {
this.$emit('activedTime', {
startDate: this.startDate,
endDate: this.endDate
});
}
},
actived(val: number) {
this.isActived = !this.isActived;
this.isActivedNumber = val;
if (val == 0) {
this.currentDate = new Date(this.startDate);
} else {
this.currentDate = new Date(this.endDate);
}
},
change() {
let curTime = this.getYYMMDD(this.currentDate);
if (this.isActivedNumber == 0) {
this.startDate = curTime;
} else {
this.endDate = curTime;
}
},
clickData() {
this.showoverlay = false;
}
},
};
</script>
css代码
<style scoped lang="scss">
.dateTemplate {
.overlayimg {
width: 140px;
height: 140px;
line-height: 140px;
vertical-align: middle;
text-align: center;
background: rgba(0, 0, 0, 0.75);
border-radius: 8px;
backdrop-filter: blur(20px);
position: absolute;
top: 33%;
left: 30%;
z-index: 1002;
img {
display: inline-block;
margin-top: -22px;
}
p {
text-align: center;
height: 21px;
font-size: 15px;
font-weight: 400;
color: #ffffff;
line-height: 21px;
margin-top: -40px;
}
}
.time {
display: flex;
justify-content: space-around;
height: 40px;
line-height: 40px;
vertical-align: middle;
background: #ffffff;
font-size: 15px;
font-weight: 400;
color: #252525;
.dataBox {
height: 14px;
font-size: 11px;
font-weight: 500;
line-height: 14px;
vertical-align: middle;
margin-top: 5px;
img {
position: relative;
top: -22px;
right: -70px;
}
}
img {
display: inline-block;
}
.istime {
color: #d02541 !important;
}
}
.date {
position: fixed;
width: 100%;
bottom: 0;
z-index: 1002;
:deep .van-picker {
border-radius: 10px 10px 0px 0px;
}
:deep .van-picker__cancel {
font-size: 17px;
font-weight: 400;
color: #252525;
}
:deep .van-picker__confirm {
font-size: 17px;
font-weight: 400;
color: #d02541;
}
:deep .van-picker__toolbar {
height: 50px;
background: #ffffff;
box-shadow: inset 0px -0.5px 0px 0px #e8e8e8;
border-radius: 10px 10px 0px 0px;
}
:deep .van-picker__columns {
margin-top: 60px;
left: 43px;
margin-right: 86px;
}
:deep .van-picker__title {
font-size: 18px;
font-weight: 500;
color: #252525;
}
:deep .van-picker-column__item {
font-size: 17px;
font-weight: 400;
color: #252525;
}
:deep .van-picker__frame {
left: 0;
right: 0;
}
.xuanze {
background: #fff;
display: flex;
justify-content: space-between;
padding: 0 45px;
position: absolute;
top: 50px;
width: 100%;
height: 70px;
line-height: 70px;
vertical-align: middle;
z-index: 3;
font-size: 15px;
font-weight: 500;
color: #252525;
// border-top: 1px solid #e8e8e8;
// box-shadow: inset 0px -1px 0px 0px #e8e8e8;
.actived {
color: #d02541;
border-bottom: 1px solid #d02541 !important;
}
.left {
width: 100%;
border-bottom: 1px solid #e8e8e8;
text-align: center;
}
span {
display: inline-block;
width: 23px;
font-size: 12px;
font-weight: 400;
color: #666666;
}
}
}
:deep .van-overlay {
background-color: rgba(0, 0, 0, 0.4);
z-index: 1000;
}
}
</style>
组件应用
//页面直接使用
<date-template @activedTime="activedTime"></date-template>
// 下面是引入组件和组件名称,自己命名就行了
import DateTemplate from '@/components/DateTemplate.vue';
components: { DateTemplate },
打印出来的res值就是拿到的时间,直接在页面使用就行了
methods: {
activedTime(res: any) {
console.log(res, 'val====');
}
}