Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run
156 lines
3.9 KiB
Vue
156 lines
3.9 KiB
Vue
|
|
<script setup>
|
|
import {nextTick, ref,computed,watch} from "vue";
|
|
import dayjs from "dayjs";
|
|
import {useCalendar} from "@/store/calendar";
|
|
const {generateCalendarData}= useCalendar()
|
|
const current = ref(1);
|
|
const swiperItems = [0, 1, 2];
|
|
const showDays=(item)=>{
|
|
if (current.value===item){
|
|
return currentDays.value
|
|
}else{
|
|
if (current.value-item===1 ||
|
|
current.value - item === -2){
|
|
return preDays.value
|
|
}else{
|
|
return nextDays.value
|
|
}
|
|
}
|
|
}
|
|
const props=defineProps({
|
|
value:{
|
|
type:String,
|
|
default:''
|
|
}
|
|
})
|
|
const swiperHeight=()=>{
|
|
return `${showDays(current.value)?.length/7 * 72}rpx`
|
|
}
|
|
const emit = defineEmits(['update:value','change-dates']);
|
|
|
|
const currentDays = ref([])
|
|
const preDays = ref([])
|
|
const nextDays = ref([])
|
|
const nextMonth = computed(()=>{
|
|
return dayjs(props.value, 'YYYY-MM').add(1, 'month').format('YYYY-MM')
|
|
})
|
|
const preMonth = computed(()=>{
|
|
return dayjs(props.value, 'YYYY-MM').subtract(1, 'month').format('YYYY-MM')
|
|
})
|
|
const initDates=()=>{
|
|
currentDays.value=generateCalendarData(props.value)
|
|
preDays.value=generateCalendarData(preMonth.value)
|
|
nextDays.value=generateCalendarData(nextMonth.value)
|
|
emit('change-dates',showDays(current.value))
|
|
}
|
|
watch(()=>props.value,()=>{
|
|
initDates()
|
|
})
|
|
const initLoad=()=>{
|
|
initDates()
|
|
}
|
|
initLoad()
|
|
function updateMonthsData(direction) {
|
|
if (direction === "prev") {
|
|
emit('update:value',preMonth.value)
|
|
} else if (direction === "next") {
|
|
emit('update:value',nextMonth.value)
|
|
}
|
|
nextTick(()=>{
|
|
initDates()
|
|
})
|
|
}
|
|
function handleSwiperChange(e) {
|
|
const pre = current.value;
|
|
const current2 = e.detail.current;
|
|
/* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周
|
|
*current - pre === 1, -2时是下一个月/周
|
|
*current -pre === -1, 2时是上一个月或者上一周
|
|
*/
|
|
current.value = current2;
|
|
if (current2 - pre === 1 || current2 - pre === -2) {
|
|
updateMonthsData('next');
|
|
} else {
|
|
updateMonthsData('prev');
|
|
}
|
|
|
|
}
|
|
const contract=ref(false)
|
|
|
|
</script>
|
|
<template>
|
|
<div class="x-calendar">
|
|
<div class="content1">
|
|
<div class="wrap1" v-for="day in ['日', '一', '二', '三', '四', '五', '六']" :key="day">
|
|
{{ day }}
|
|
</div>
|
|
</div>
|
|
<div class="content4"></div>
|
|
<div class="content2"></div>
|
|
<swiper :duration="500" :current="current" :style="{height: contract?'72rpx':swiperHeight(),transition: `height 0.2s ease`}" :indicator-dots="false" :circular="true" @change="handleSwiperChange">
|
|
<swiper-item v-for="(item, index) in swiperItems" :key="item">
|
|
<div class="content3">
|
|
<div class="wrap1" v-for="(day,index1) in showDays(item)" :key="day.date">
|
|
<slot name="cell" :data="day" :index="index1" ></slot>
|
|
</div>
|
|
</div>
|
|
</swiper-item>
|
|
</swiper>
|
|
<div class="content5" @click="contract=!contract">
|
|
<div :class="`triangle ${contract?'rotate':''}`"></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<style scoped lang="scss">
|
|
.x-calendar {
|
|
.content5{
|
|
padding-top: 22rpx;
|
|
padding-bottom: 22rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
.triangle {
|
|
width: 0;
|
|
height: 0;
|
|
border-left: 14rpx solid transparent;
|
|
border-right: 14rpx solid transparent;
|
|
border-bottom: 12rpx solid #C2C2C2;
|
|
&.rotate{
|
|
transform: rotate(180deg);
|
|
}
|
|
}
|
|
}
|
|
.content4{
|
|
margin-top: 32rpx;
|
|
width: 100%;
|
|
height: 1rpx;
|
|
background-color: #EFEFF5;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
.content3 {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
.wrap1 {
|
|
flex: 1 0 calc(100% / 7);
|
|
}
|
|
}
|
|
|
|
.content1 {
|
|
margin-top: 46rpx;
|
|
display: flex;
|
|
.wrap1 {
|
|
font-size: 28rpx;
|
|
color: #191919;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
flex-grow: 1;
|
|
}
|
|
}
|
|
.content2 {
|
|
height: 4rpx;
|
|
}
|
|
}
|
|
</style>
|