这是我再一个博主的基础上改的
详情请看:https://blog.csdn.net/weixin_41277748/article/details/122847305
我是单独写了一个组件!
<template>
<div class="w-calender-container">
<div class="select_date">选择日期</div>
<div class="w-top">
<div class="w-top-date">
<div @click="handleShowLastMonth">
<i class="el-icon-arrow-left"></i>
</div>
<div style="margin: 0 15px">
{{ year }}年{{ `${month > 9 ? month : "0" + month}` }}月
</div>
<div @click="handleShowNextMonth">
<i class="el-icon-arrow-right"></i>
</div>
</div>
</div>
<div class="w-date_wrap">
<ul class="w-week">
<li>日</li>
<li>一</li>
<li>二</li>
<li>三</li>
<li>四</li>
<li>五</li>
<li>六</li>
</ul>
<ul class="w-day">
<li
v-for="(item, index) in days"
:class="{
'c-isCurMonth': item.isNextMonth || item.isLastMonth,
'c-isCurToday': item.isCurToday,
'c-isActive': item.isActive,
'c-is-previous-date': item.isPreviousDate,
}"
:key="index"
@click="handleChooseDay(item)"
>
<span>
{{ item.day }}
</span>
<span v-if="item.isShowPoint" class="w-point"></span>
</li>
</ul>
</div>
</div>
</template>
<script>
// import { getCurDay } from "@/util/MyTools";
export default {
name: "calender",
props: {
//是否是多选
isMultipleChoice: {
type: Boolean,
default: true,
},
//是否显示清除按钮
isShowClear: {
type: Boolean,
default: true,
},
//选择的月份
Month: {
type: String,
},
//需要加圆点的数据
//数据格式为map { new Date(2022-02-11).getTime():true}: 用年月日的时间戳为key
pointMap: {
type: Object,
default: () => {
return {};
},
},
//是否禁止选择以前的日期 默认为空表示没有限制 注:如果只有数字则 默认时间是当天时间
//{1:['2022-02-11']}表示2022-02-11以前的日期不能选择;1:表示小于该时间的禁止选择,必填
//{2:['2022-02-11']}表示2022-02-11以后的日期不能选择;2:表示大于该时间的禁止选择,必填
//{3:['2022-02-11','2022-03-11']}表示2022-02-11到2022-03-11之间的日期可以选择;3:表示两个时间内的时间可以选择,必填
//{4:['2022-02-11','2022-03-11']}表示2022-02-11到2022-03-11之外的日期可以选择;4:表示两个时间之外的可以选择,必填
restrictDate: {
type: Object,
default: () => {
return null;
},
},
},
watch: {
Month: {
handler(val) {
if (val) {
const date = val.split("-").map(Number);
this.year = date[0];
this.month = date[1];
this.days = [];
//选择月份后重新跟更新时间
this.dealDate();
}
},
immediate: true,
},
pointMap: {
handler(val) {
if (val) {
this.dealDate();
}
},
immediate: true,
},
},
data() {
return {
year: "", //年
month: "", //月
days: [], //日期
//是否已经选择了开始时间
isChooseOne: false,
endTime: null,
startTime: null,
monthValue: "", //选择的月份
chooseDateList: {}, //如果是单选 则把选择的保存
};
},
methods: {
//得到当前年这个月分有多少天
getDays(Y, M) {
return new Date(Y, M, 0).getDate();
},
//得到当前年,这个月的一号是周几
getWeek(Y, M) {
let now = new Date();
now.setFullYear(this.year);
now.setMonth(this.month - 1);
now.setDate(1);
return now.getDay();
},
/**
* 获取本月日期
*/
pushDays() {
//将这个月多少天加入数组days
const m = `${this.month > 9 ? this.month : "0" + this.month}`;
for (let i = 1; i <= this.getDays(this.year, this.month); i++) {
const d = `${i > 9 ? i : "0" + i}`,
date = `${this.year}-${m}-${d}`;
this.days.push({
day: d,
isActive: false,
month: m,
year: `${this.year}`,
date,
timestamp: new Date(date).getTime(), //转换时间戳
});
}
//获取上个月的日期
this.getLastMonthDays();
//获取下个月的日期
this.getNextMonthDays();
},
/**
* 获取下个月的日期
*/
getNextMonthDays() {
const m = this.month < 12 ? this.month + 1 : 1,
y = this.month < 12 ? this.year : this.year + 1,
len =
42 -
this.getDays(this.year, this.month) -
this.getWeek(this.year, this.month),
_m = `${m > 9 ? m : "0" + m}`;
//将下个月要显示的天数加入days
for (let i = 1; i <= len; i++) {
const _d = `${i > 9 ? i : "0" + i}`,
date = `${y}-${_m}-${_d}`;
this.days.push({
day: _d,
month: _m,
year: `${y}`,
isActive: false,
isNextMonth: true,
date,
timestamp: new Date(date).getTime(),
});
}
},
/**
* 获取上个月的日期
*/
getLastMonthDays() {
const m = this.month > 1 ? this.month - 1 : this.year > 1970 ? 12 : 1,
y =
this.month > 1 ? this.year : this.year > 1970 ? this.year - 1 : 1970,
len = this.getWeek(this.year, this.month),
lastMonthDays = this.getDays(this.year, this.month - 1);
//将上个月要显示的天数加入days
for (let i = 0; i < len; i++) {
const _m = `${m > 9 ? m : "0" + m}`,
date = `${y}-${_m}-${lastMonthDays - i}`;
this.days.unshift({
day: `${lastMonthDays - i}`,
month: _m,
year: `${y}`,
isActive: false,
isLastMonth: true,
date,
timestamp: new Date(date).getTime(),
});
}
},
/**
* 上个月
*/
handleShowLastMonth() {
if (this.month > 1) {
this.month = this.month - 1;
} else if (this.year > 1970) {
this.month = 12;
this.year = this.year - 1;
}
this.dealDate();
},
/**
* 下个月
*/
handleShowNextMonth() {
this.days = [];
if (this.month < 12) {
this.month = this.month + 1;
} else {
this.month = this.month = 1;
this.year = this.year + 1;
}
this.dealDate();
},
/**
* 当天
*/
handleShowToday() {
let now = new Date();
this.year = now.getFullYear();
this.month = now.getMonth() + 1;
this.dealDate();
},
// 获取当天日期
getCurDay() {
var datetime = new Date();
var year = datetime.getFullYear();
var month =
datetime.getMonth() + 1 < 10
? "0" + (datetime.getMonth() + 1)
: datetime.getMonth() + 1;
var date =
datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
return `${year}-${month}-${date}`;
},
/**
* 处理时间
*/
dealDate() {
this.days = [];
console.log(44);
console.log(5555, this.getCurDay());
const curDate = this.getCurDay();
this.pushDays();
// 判断 是否需要禁止选择某些时间段的时间
if (this.restrictDate) {
const keys = Object.keys(this.restrictDate);
let day, timestamp;
switch (keys[0]) {
case "1":
day =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]]) ||
curDate;
timestamp = new Date(day).getTime(); //转换时间戳
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
item.isPreviousDate = item.timestamp < timestamp;
});
break;
case "2":
day =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]]) ||
curDate;
timestamp = new Date(day).getTime(); //转换时间戳
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
item.isPreviousDate = item.timestamp > timestamp;
});
break;
case "3":
const s_d =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]][1]) ||
curDate;
const e_d =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]][2]) ||
curDate;
let s = new Date(s_d).getTime(),
e = new Date(e_d).getTime();
if (s > e) {
[s, e] = [e, s];
}
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
item.isPreviousDate = item.timestamp > s && item.timestamp < e;
});
break;
case "4":
const st_d =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]][1]) ||
curDate;
const en_d =
(this.restrictDate[keys[0]] && this.restrictDate[keys[0]][2]) ||
curDate;
let st = new Date(st_d).getTime(),
en = new Date(en_d).getTime();
if (st > en) {
[st, en] = [en, st];
}
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
item.isPreviousDate = item.timestamp < st || item.timestamp > en;
});
break;
default:
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
});
}
} else {
this.days.forEach((item) => {
item.isCurToday = item.date === curDate;
});
}
this.getActiveDay();
},
/**
* 清空选择
*/
handleClear() {
this.isChooseOne = false;
this.startTime = null;
this.endTime = null;
this.chooseDateList = {};
this.days.forEach((item) => {
item.isActive = false;
});
},
/**
* 选择时间
* @param time
*/
handleChooseDay(time = {}) {
// 判断 是否是禁止选择的日期 是否是
if (this.restrictDate && time.isPreviousDate) {
return;
}
//是否是多选
if (this.isMultipleChoice) {
this.chooseDateList = {};
//选择开始时间-结束时间
if (this.isChooseOne) {
this.endTime = time;
const { timestamp } = this.startTime || {};
//如果 选择的开始日期大于结束日期 则调换开始日期与结束日期
if (timestamp > time.timestamp) {
[this.startTime, this.endTime] = [this.endTime, this.startTime];
}
this.getActiveDay();
this.isChooseOne = false;
this.$emit("chooseDays", this.chooseDateList);
} else {
this.isChooseOne = true;
this.startTime = time;
//给选择的时间范围选中
this.days.forEach((item) => {
item.isActive = item.timestamp === this.startTime.timestamp;
});
}
} else {
this.days.forEach((item) => {
if (item.timestamp === time.timestamp) {
item.isActive = !time.isActive;
if (time.isActive) {
const { date, day, month, timestamp, year } = item;
this.chooseDateList[time.timestamp] = {
date,
day,
month,
timestamp,
year,
};
} else {
delete this.chooseDateList[time.timestamp];
}
}
});
this.$emit("chooseDays", this.chooseDateList);
}
},
/**
* 给选择的日期范围加上选中状态
*/
getActiveDay() {
if (this.isMultipleChoice) {
if (!this.startTime || !this.endTime) {
return;
}
//给选择的时间范围选中
const { timestamp } = this.startTime || {};
const { timestamp: endTimestamp } = this.endTime || {};
this.days.forEach((item) => {
item.isActive =
item.timestamp >= timestamp &&
item.timestamp <= endTimestamp &&
!item.isPreviousDate;
//是否显示点
item.isShowPoint = this.pointMap[item.timestamp];
if (
item.timestamp >= timestamp &&
item.timestamp <= endTimestamp &&
!item.isPreviousDate
) {
const { date, day, month, timestamp, year } = item;
this.chooseDateList[item.timestamp] = {
date,
day,
month,
timestamp,
year,
};
} else {
delete this.chooseDateList[item.timestamp];
}
});
} else {
this.days.forEach((item) => {
//是否显示点
item.isShowPoint = this.pointMap[item.timestamp];
//已选择的数据加上状态
item.isActive = !!this.chooseDateList[item.timestamp];
});
}
},
},
mounted() {
this.handleShowToday();
},
};
</script>
<style>
ul {
list-style: none;
}
.w-calender-container {
margin: auto;
width: 550px;
height: 500px;
/* border: 1px solid #ddd; */
box-sizing: border-box;
}
.select_date {
width: 100%;
text-align: center;
font-size: 14px;
color: #000;
font-weight: 600;
}
.w-top {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 1% 0;
/* border-bottom: 1px solid #ddd; */
box-sizing: border-box;
}
.w-top .w-top-date {
display: flex;
align-content: center;
white-space: nowrap;
}
.w-top .w-btn-wrap {
min-width: 200px;
display: flex;
justify-content: space-around;
color: #f26520;
}
.w-btn-wrap span {
flex: 1;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
}
.w-btn-wrap span:last-child {
color: #ff6200;
}
.w-date_wrap {
width: 100%;
height: auto;
}
.w-date_wrap .w-week {
width: 100%;
display: flex;
flex-direction: row;
padding: 10px 0 10px 40px;
font-size: 16px;
box-sizing: border-box;
}
.w-date_wrap .w-week li {
width: 14.28%;
}
.w-date_wrap .w-day {
width: 100%;
display: flex;
flex-direction: row;
padding: 0 20px;
font-size: 16px;
flex-wrap: wrap;
box-sizing: border-box;
}
.w-day li {
position: relative;
cursor: pointer;
width: 14.28%;
padding: 4%;
/* border: 1px solid #ddd; */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.w-day li .w-point {
position: absolute;
bottom: 26%;
background: #ff0000;
display: flex;
width: 4px;
height: 4px;
border-radius: 50%;
}
.w-day li:nth-child(n + 8) {
border-top: none;
}
.w-day li:nth-child(n + 1) {
border-right: none;
}
.w-day li:nth-child(7n) {
/* border-right: 1px solid #ddd; */
}
.c-isCurMonth {
background: #fff;
color: #c0c4cc;
}
.c-isCurToday {
background: #fff;
color: #f26520;
}
.c-isActive {
background: #f26520;
color: #f2f8fe;
}
.chooseMonth {
width: 120px;
}
.isCurYearDay {
cursor: not-allowed !important;
opacity: 0.6;
}
.c-isCurMonth.c-isActive {
background: #f26520;
}
.c-is-previous-date {
background: rgba(192, 196, 204, 0.2);
color: #c0c4cc;
cursor: not-allowed !important;
}
</style>
父组件:
<el-dialog
title="请选择时间"
v-if="dialogTimeVisible"
custom-class="timeDialog"
:visible.sync="dialogTimeVisible"
width="45%"
>
<dayTime @chooseDays="chooseDays"></dayTime>
<div class="btn_cir">
<el-button>取消</el-button>
<el-button type="primary" @click="onCirmentClick">确定</el-button>
</div>
</el-dialog>
chooseDays(v) {
let list = Object.values(v);
if (this.timeState == 1) {
this.timevalue = `${list[0].date} - ${list[list.length - 1].date}`;
} else {
this.inputTimeVlue = `${list[0].date} - ${list[list.length - 1].date}`;
}
// 拿到对象中的第一条数据
// let day = v[Object.keys(v)[0]];
// 对象转换成数组
},