209 lines
4.1 KiB
Vue
209 lines
4.1 KiB
Vue
<template>
|
|
<view class="calendar">
|
|
<view class="header">
|
|
<view class="header-title">
|
|
<view class="year-month">{{ year }}年{{ month + 1 }}月</view>
|
|
<view class="botton-father">
|
|
<view class="click-button" @click="prevMonth">上个月</view>
|
|
<view class="click-button" @click="nextMonth">下个月</view>
|
|
</view>
|
|
</view>
|
|
<view class="weekdays">
|
|
<view v-for="(day, idx) in weekdays" :key="idx" class="weekday">{{ day }}</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="days">
|
|
<view v-for="cell in cells" :key="cell.key" class="day-cell" :class="{
|
|
'prev-month': cell.prev,
|
|
'next-month': cell.next,
|
|
selected: isSelected(cell.key)
|
|
}" @click="selectDate(cell)">
|
|
<view class="gregorian">{{ cell.dateText }}</view>
|
|
<view class="lunar" v-if="cell.lunarText">{{ cell.lunarText }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
ref,
|
|
computed
|
|
} from 'vue';
|
|
import solarlunar from 'solarlunar'; // npm install solarlunar
|
|
|
|
const now = new Date();
|
|
const year = ref(now.getFullYear());
|
|
const month = ref(now.getMonth());
|
|
|
|
// 单选选中 key
|
|
const selectedKey = ref(null);
|
|
|
|
// 星期一到星期日
|
|
const weekdays = ['一', '二', '三', '四', '五', '六', '日'];
|
|
|
|
const firstWeekdayOfMonth = (y, m) => {
|
|
const d = new Date(y, m, 1).getDay();
|
|
return (d + 6) % 7;
|
|
};
|
|
|
|
const cells = computed(() => {
|
|
const list = [];
|
|
const prevMonthDate = new Date(year.value, month.value, 0);
|
|
const prevYear = prevMonthDate.getFullYear();
|
|
const prevMonth = prevMonthDate.getMonth();
|
|
const prevTotal = prevMonthDate.getDate();
|
|
const startOffset = firstWeekdayOfMonth(year.value, month.value);
|
|
for (let i = 0; i < startOffset; i++) {
|
|
const day = prevTotal - startOffset + i + 1;
|
|
const lunar = solarlunar.solar2lunar(prevYear, prevMonth + 1, day);
|
|
list.push({
|
|
key: `prev-${prevYear}-${prevMonth + 1}-${day}`,
|
|
dateText: day,
|
|
lunarText: lunar.dayCn,
|
|
prev: true,
|
|
next: false,
|
|
});
|
|
}
|
|
|
|
const totalDays = new Date(year.value, month.value + 1, 0).getDate();
|
|
for (let d = 1; d <= totalDays; d++) {
|
|
const lunar = solarlunar.solar2lunar(year.value, month.value + 1, d);
|
|
list.push({
|
|
key: `${year.value}-${month.value + 1}-${d}`,
|
|
dateText: d,
|
|
lunarText: lunar.dayCn,
|
|
prev: false,
|
|
next: false,
|
|
});
|
|
}
|
|
|
|
return list;
|
|
});
|
|
|
|
function isSelected(key) {
|
|
return selectedKey.value === key;
|
|
}
|
|
|
|
function selectDate(cell) {
|
|
if (cell.prev) {
|
|
return
|
|
}
|
|
selectedKey.value = cell.key;
|
|
// 触发导出事件或回调
|
|
console.log('Selected date:', cell.key);
|
|
}
|
|
|
|
function prevMonth() {
|
|
if (month.value === 0) {
|
|
year.value--;
|
|
month.value = 11;
|
|
} else {
|
|
month.value--;
|
|
}
|
|
}
|
|
|
|
function nextMonth() {
|
|
if (month.value === 11) {
|
|
year.value++;
|
|
month.value = 0;
|
|
} else {
|
|
month.value++;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.calendar {
|
|
padding: 16px;
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.header-title {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.year-month {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.botton-father {
|
|
display: flex;
|
|
margin-top: -20rpx;
|
|
}
|
|
|
|
.click-button {
|
|
padding: 10rpx;
|
|
width: 120rpx;
|
|
font-size: 25rpx;
|
|
height: 40rpx;
|
|
margin-right: 10rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
color: #fff;
|
|
background-color: #888;
|
|
border-radius: 10rpx;
|
|
}
|
|
|
|
.weekdays {
|
|
display: flex;
|
|
background-color: #E9E7FC;
|
|
border-radius: 30rpx;
|
|
padding: 10rpx;
|
|
}
|
|
|
|
.weekday {
|
|
flex: 1;
|
|
text-align: center;
|
|
}
|
|
|
|
.days {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
padding: 10rpx;
|
|
}
|
|
|
|
.day-cell {
|
|
width: 73.5rpx;
|
|
height: 80.5rpx;
|
|
text-align: center;
|
|
padding-top: 8rpx;
|
|
padding-bottom: 8rpx;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.day-cell.prev-month .gregorian,
|
|
.day-cell.next-month .gregorian {
|
|
color: #ccc;
|
|
}
|
|
|
|
/* 选中样式 */
|
|
.day-cell.selected {
|
|
background-color: #0B98DC;
|
|
border-radius: 10rpx;
|
|
}
|
|
|
|
.day-cell.selected .gregorian,
|
|
.day-cell.selected .lunar {
|
|
color: #fff;
|
|
}
|
|
|
|
.gregorian {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.lunar {
|
|
font-size: 10px;
|
|
color: #888;
|
|
}
|
|
</style> |