<template>
<!-- 选择年月 picker -->
<van-popup v-model:show="state.showTime" position="bottom">
<van-datetime-picker
v-model="state.defaultDate"
type="year-month"
title="选择年月"
:min-date="state.minDate"
:max-date="state.maxDate"
@cancel="state.showTime = false"
@confirm="confirm"
/>
</van-popup>
<div class="root">
<div class="common">
<div class="common_header" @click="state.showTime = true">
{{ state.date }} <van-icon name="arrow" />
</div>
<div class="date_box">
<!-- 星期 -->
<div class="week">
<span v-for="(item, index) in week" :key="index">{{ item }}</span>
</div>
<!-- 日 -->
<div class="day">
<div
class="day_item"
:class="[
state.selectMonth != item.month
? 'dust'
: state.activeIndex == index
? 'active'
: '',
]"
v-for="(item, index) in state.list"
:key="index"
>
<span class="num" @click="handleToggle(index, item)">{{
item.date
}}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive } from "vue";
import dayjs from "dayjs";
const emits = defineEmits(["select"]);
const week = ["日", "一", "二", "三", "四", "五", "六"];
const state = reactive({
// picker
minDate: new Date(2010, 1, 1),
maxDate: new Date(),
defaultDate: new Date(),
// 日期数据
list: [],
// 默认当前日期
date: dayjs().format("YYYY年MM月"),
showTime: false,
selectMonth: dayjs().format("M"),
activeIndex: -1,
});
onMounted(() => {
dateListInit();
state.activeIndex = state.list.findIndex(
(item) => item.dateString == dayjs().format("YYYY-MM-DD")
);
emits("select", dayjs().format("YYYY-MM-DD"));
});
// 点击日历日期
function handleToggle(index, item) {
if (item.month != state.selectMonth) return;
state.activeIndex = index;
emits("select", item?.dateString);
}
// picker 确认
function confirm(val) {
state.date = dayjs(val).format("YYYY年M月");
state.selectMonth = dayjs(val).format("M");
state.showTime = false;
dateListInit(dayjs(val).format("YYYY"), dayjs(val).format("M"));
}
/**
* 构造数据
* @param {number} year
* @param {number} month
*/
function dateListInit(
year = Number(dayjs().format("YYYY")),
month = Number(dayjs().format("M"))
) {
//需要遍历的日历数组数据
let dateList = [];
//日历渲染开始日期
let startDate = dayjs(`${year}-${month}`).day(0);
//日历主体渲染结束日期
let endDate = dayjs(`${year}-${month}`).endOf("month").day(6);
// 循环构造数据
while (startDate < endDate) {
const dateString = startDate.format("YYYY-MM-DD");
dateList.push({
date: startDate.date(),
month: startDate.month() + 1,
year: startDate.year(),
dateString,
});
startDate = startDate.add(1, "day");
}
state.list = dateList;
}
</script>
<style lang="scss" scoped>
.root {
font-size: 28px;
background-color: #f6f6f6;
height: calc(100vh - var(--van-nav-bar-height));
overflow: auto;
padding: 20px 32px;
box-sizing: border-box;
.common {
background: #ffffff;
border-radius: 16px;
margin-bottom: 20px;
&_header {
font-size: 28px;
font-weight: bold;
color: var(--van-primary-color);
line-height: 40px;
padding: 32px;
border-bottom: 2px solid #eee;
}
.date_box {
padding: 32px 0;
.week {
display: flex;
align-items: center;
text-align: center;
margin-bottom: 24px;
span {
width: 98px;
}
}
.day {
display: flex;
flex-wrap: wrap;
&_item {
width: 98px;
height: 98px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&.dust {
.num {
color: #999999;
}
}
&.active {
.num {
width: 60px;
height: 60px;
line-height: 60px;
text-align: center;
border-radius: 50%;
background-color: #316eeb;
color: #fff;
}
}
.num {
font-size: 26px;
color: #333333;
line-height: 36px;
}
}
}
.time_box {
padding: 32px;
.item {
display: flex;
align-items: center;
margin-bottom: 32px;
&:last-of-type {
margin-bottom: 0;
}
.title {
width: 60px;
text-align: right;
font-size: 26px;
font-weight: bold;
color: var(--van-primary-color);
line-height: 36px;
}
.line {
width: 4px;
height: 70px;
background: #eeeeee;
margin-right: 32px;
margin-left: 32px;
}
.content {
background-color: #f8f8f8;
border-radius: 16px;
padding: 12px 24px;
flex: 1;
display: flex;
flex-direction: column;
.time {
font-size: 26px;
color: #333333;
line-height: 36px;
}
.desc {
font-size: 24px;
color: #999999;
line-height: 34px;
}
}
}
}
}
}
}
</style>
使用
<Calendar @select="select" />
function select(item) {
console.log("1", item);
}
构造星期
onMounted(() => {
let details = [];
// 8 为下周 1 为当前周
let num = true ? 8 : 1;
for (let i = 0; i < 7; i++) {
let temp = dayjs()
.startOf("week")
.add(`${i * 1 + num}`, "day")
.format("YYYY-MM-DD");
details.push({
date: temp,
});
}
console.log(details);
// [
// {date: "2022-08-08"}
// {date: "2022-08-09"}
// {date: "2022-08-10"}
// {date: "2022-08-11"}
// {date: "2022-08-12"}
// {date: "2022-08-13"}
// {date: "2022-08-14"}
// ]
});