The vant Calendar component displays a single month, can switch months, expands and collapses the display date function

Use scenario description:

1. Display the date data of a single month, click to switch the month data
Please add a picture description
 
2. Click the date to close the calendar (display a week), and then click to expand the calendar (display the entire month)
Please add a picture description
ps: This example is written in typescript

html template
<div class="calendar">
    <div class="calendar-top">
      <div class="calendar-top-title">学习表</div>
      <div class="calendar-top-button">
        <img
          src="../../assets/img/outside/icxxbgsy18.png"
          alt=""
          class="button-icon"
          @click="arrowLeft()"
        />
        <div class="calendar-top-time" @click="clickDate">
          {
   
   { year }}-{
   
   { month + 1 }}
        </div>
        <img
          src="../../assets/img/outside/icxxbgsy17.png"
          alt=""
          class="button-icon"
          @click="arrowRight()"
        />
      </div>
    </div>
    <van-calendar
      class="calendar-main"
      :class="showAllMonth ? 'open' : 'close'"
      :show-title="false"
      :poppable="false"
      :show-confirm="false"
      :show-mark="false"
      :default-date="defaultDate"
      :min-date="minDate"
      :max-date="maxDate"
      :formatter="formatter"
      @select="selectDay"
      first-day-of-week="1"
      row-height="35px"
      ref="calendar"
    />
  </div>
template parsing

The calendar component of vant is mainly used . The selected month is displayed on the top of the component and the button controls the switching month, which are the arrowLeft() function and the arrowRight() function.
Please add a picture description

Display date data of a single month, click to switch month data

1. Create a function to set the currently displayed month calendar, mainly to modify min-date and max-date. Called when data is initialized (such as onMounted), and the current month is passed in as a parameter.

//设置当前显示日历
const setDate = (month: number) => {
    
    
  //计算传入的月份天数
  const daycount = new Date(year.value, month + 1, 0).getDate()
  //将1号设置成可选择最小日期
  let monthMin = new Date(year.value, month, 1)
  //将传入月份的最后一天设置成可选择最大日期
  let monthMax = new Date(year.value, month, daycount)
  //已在setup中初始化minDate和maxDate(minDate=ref())
  minDate.value = monthMin
  maxDate.value = monthMax
}

2. Switch the previous month's calendar

const arrowLeft = function () {
    
    
  //将当前所在月份减一,并传入setDate()函数
  month.value --
  setDate(month.value)
}

3. Switch calendar for next month

const arrowRight= function () {
    
    
  //将当前所在月份加一,并传入setDate()函数
  month.value ++
  setDate(month.value)
}

You can make some judgments in arrowLeft () and arrowRight () to limit the months that can be switched. For example, month.value cannot always be reduced to a negative number, or cannot be added to exceed 12. If you are lazy, I will not write it here~~

Click the date to close the calendar, then click to expand the calendar

//获取实例(vue3写法)
import {
    
     getCurrentInstance } from "vue"
const {
    
     proxy } = getCurrentInstance() as any

//点击日期响应函数
const clickDate = function () {
    
    
  //showAllMonth:是否展开日历
  showAllMonth.value = !showAllMonth.value
  let calendarMain = <HTMLElement>(
    document.getElementsByClassName("calendar-main")[0]
  )
  if (showAllMonth.value) {
    
    
    //展开,用样式控制
    calendarMain.style.height = "225px"
  } else {
    
    
   //收起,用样式控制
    calendarMain.style.height = "70px"
    //获得当前选择的日期(本例子是将选中日期的时间戳存在store中)
    //转时间戳是本例子项目需要,也可以不转时间戳直接date形式就行
    let date = new Date(baseStore.selectTimestamp * 1000)
    //将选中日期重置到当前选中的日期,不然收起后选中的是1号,并且是显示1号所在的那个星期
    proxy.$refs.calendar.reset(date)
  }
}
//选中任意日期响应函数
const selectDay = function (day: any) {
    
    
  // console.log(day)//选中的日期
  const timestamp = Date.parse(day) / 1000 //转时间戳
  //存store
  baseStore.$patch((state) => {
    
    
    state.selectTimestamp = timestamp
  })
}

This is the end of the sharing of the two functions, and the others are controlled by styles, modifying the styles in the vant component. You need to use ::v-deep to select the element class, for example::v-deep(.van-calendar). The style class name of the vant component can be checked by pressing F12 to select the element in the browser to view the class name.
just for reference:

::v-deep(.van-calendar) {
    
    
  width: 106%;
  margin-left: -3%;
  background: none;
}
//在数字前面加上周字
::v-deep(.van-calendar__weekday::before) {
    
    
  content: "周";
  color: rgba($color: #000000, $alpha: 0.5);
}

------------------------------------------------ This is a dividing line ---------------------------------------------

Meet the requirements of the buddies in the comment area, and post the source code. I am helpless when I can’t write and search everywhere. I hope I can help you code friends (I have forgotten the thinking at that time QAQ after a long time)

<template>
  <div class="calendar">
    <div class="calendar-top">
      <div class="calendar-top-title">学习表</div>
      <div class="calendar-top-button">
        <img
          src="../../assets/img/outside/icxxbgsy18.png"
          alt=""
          class="button-icon"
          @click="arrowLeft()"
        />
        <div class="calendar-top-time" @click="clickDate">
          {
    
    {
    
     year }}-{
    
    {
    
     month + 1 }}
        </div>
        <img
          src="../../assets/img/outside/icxxbgsy17.png"
          alt=""
          class="button-icon"
          @click="arrowRight()"
        />
      </div>
    </div>
    <van-calendar
      class="calendar-main"
      :show-title="false"
      :poppable="false"
      :show-confirm="false"
      :show-mark="false"
      :default-date="defaultDate"
      :min-date="minDate"
      :max-date="maxDate"
      :formatter="formatter"
      @select="selectDay"
      first-day-of-week="1"
      row-height="35px"
      ref="calendar"
    />
  </div>
</template>

<script lang="ts" setup>
import {
    
    
  ref,
  reactive,
  watch,
  onMounted,
  computed,
  onActivated,
  getCurrentInstance,
} from "vue"
import {
    
     GetCalendar } from "../../api/appBase"
import {
    
     useUserStore } from "../../store/model/user"
import {
    
     useBaseStore } from "../../store/model/appBase"
const userStore = useUserStore()
const baseStore = useBaseStore()
const {
    
     proxy } = getCurrentInstance() as any

let dayDatas = reactive({
    
     days: [] })

let defaultDate = ref(new Date())
let year = ref(defaultDate.value.getFullYear())
let month = ref(defaultDate.value.getMonth())
let currentMonth = ref(defaultDate.value.getMonth())
let showAllMonth = ref(false)

let minDate = ref()
let maxDate = ref()

const formatter = (day: any) => {
    
    
  // console.log(dayDatas)
  //给有数据的日期加点
  let isHasData = false
  let dayTimestamp = Date.parse(day.date)
  dayDatas.days.forEach((item) => {
    
    
    if (dayTimestamp == item["date"] * 1000) isHasData = true
  })
  if (isHasData) {
    
    
    day.className = "addDot"
  }
  //日期被选中并且有数据
  let selectDayTimestamp = baseStore.selectTimestamp * 1000
  if (dayTimestamp == selectDayTimestamp && isHasData) {
    
    
    day.className = "addDot_Select"
  }
  //当天日期加样式
  let todayTimestamp = new Date(new Date().toDateString()).getTime()
  if (dayTimestamp == todayTimestamp) {
    
    
    day.className = "calendarToday"
  }
  //当天日期有数据
  if (dayTimestamp == todayTimestamp && isHasData) {
    
    
    day.className = "addDot_calendarToday"
  }
  return day
}

//初始化 从接口获得数据
const GetCalendarData = function (year: any, month: any) {
    
    
  const grade = userStore.getGrade
  const mode = 0
  GetCalendar({
    
     year, month, stage: grade, mode }).then((res) => {
    
    
    // console.log(res.data)
    dayDatas.days = res.data
  })
}

//设置当前显示日历
const setDate = (month: number) => {
    
    
  const daycount = new Date(year.value, month + 1, 0).getDate()
  let monthMin = new Date(year.value, month, 1)
  let monthMax = new Date(year.value, month, daycount)
  minDate.value = monthMin
  maxDate.value = monthMax
}

//切换上个月
const arrowLeft = function () {
    
    
  // console.log("<")
  if (month.value != currentMonth.value - 1) {
    
    
    month.value = currentMonth.value - 1
    setDate(month.value)
    GetCalendarData(year.value, month.value + 1)
    let day = new Date(
      year.value,
      month.value,
      new Date(year.value, month.value + 1, 0).getDate()
    )
    selectDay(day)
  } else {
    
    
    proxy.$toast({
    
    
      message: "仅保留本月和上个月的记录哦",
      icon: new URL(`../../assets/img/outside/icxxbgsy28.png`, import.meta.url)
        .href,
      className: "toast-c",
    })
  }
}

//切换下个月
const arrowRight = function () {
    
    
  // console.log(">")
  if (month.value < currentMonth.value) {
    
    
    month.value++
    setDate(month.value)
    GetCalendarData(year.value, month.value + 1)
    let day = new Date(year.value, month.value, 1)
    selectDay(day)
  } else {
    
    
    proxy.$toast({
    
    
      message: "仅保留本月和上个月的记录哦",
      icon: new URL(`../../assets/img/outside/icxxbgsy28.png`, import.meta.url)
        .href,
      className: "toast-c",
    })
  }
}

const selectDay = function (day: any) {
    
    
  // console.log(day)
  const timestamp = Date.parse(day) / 1000
  baseStore.$patch((state) => {
    
    
    state.selectTimestamp = timestamp
  })
}

const clickDate = function () {
    
    
  showAllMonth.value = !showAllMonth.value
  let calendarMain = <HTMLElement>(
    document.getElementsByClassName("calendar-main")[0]
  )
  if (showAllMonth.value) {
    
    
    calendarMain.style.height = "225px"
  } else {
    
    
    calendarMain.style.height = "68px"
    let date = new Date(baseStore.selectTimestamp * 1000)
    proxy.$refs.calendar.reset(date)
  }
}   

//特属于keepAlive的一个生命周期,activated在页面每次进入都会执行
onActivated(() => {
    
    
  if (baseStore.selectTimestamp != 0) {
    
    
    defaultDate.value = new Date(baseStore.selectTimestamp * 1000)
  }
  year.value = defaultDate.value.getFullYear()
  month.value = defaultDate.value.getMonth()
  GetCalendarData(year.value, month.value + 1)
  setDate(month.value)
  let calendarMain = <HTMLElement>(
    document.getElementsByClassName("calendar-main")[0]
  )
  calendarMain.style.height = "70px"
})

watch(
  () => userStore.getGrade,
  (newVal, oldVal) => {
    
    
    GetCalendarData(year.value, month.value + 1)
  }
)
</script>

<style lang="scss" scoped>
.calendar {
    
    
  // border: 1px solid red;
  margin-bottom: 46px !important;
  .calendar-top {
    
    
    margin-bottom: 16px;
    display: flex;
    justify-content: space-between;
    .calendar-top-title {
    
    
      font-size: 32px;
      font-weight: bold;
    }
    .calendar-top-button {
    
    
      display: flex;
      font-size: 28px;
      align-items: center;
      .button-icon {
    
    
        width: 32px;
        height: 32px;
      }
      .calendar-top-time {
    
    
        color: rgba($color: #007aea, $alpha: 0.5);
        margin: 0 10px;
      }
    }
  }

  .calendar-weekdays {
    
    
    display: flex;
    height: 50px;
    justify-content: space-between;
    align-items: center;
    // border: 1px solid red;
    .calendar-weekdays-item {
    
    
      width: 50px;
      font-size: 20px;
      color: rgba($color: #000000, $alpha: 0.5);
      // border: 1px solid red
    }
  }
  .calendar-days {
    
    
    display: grid;
    grid-template-columns: repeat(7, 8%);
    grid-row-gap: 14px;
    height: 50px;
    justify-content: space-between;
    align-items: center;
    .calendar-days-item {
    
    
      flex-shrink: 0;
      width: 50px;
      font-size: 28px;
      color: #000000;
      // border: 1px solid red;
    }
  }
}
::v-deep(.van-calendar) {
    
    
  width: 106%;
  margin-left: -3%;
  background: none;
}
::v-deep(.van-calendar__body) {
    
    
  overflow: hidden;
}
::v-deep(.van-calendar__header) {
    
    
  box-shadow: none;
}
// ::v-deep(.van-calendar__day) {
    
    
//   margin-bottom: 6px !important;
// }
::v-deep(.van-calendar__selected-day) {
    
    
  border-radius: 50%;
  background-color: #59afff !important;
  z-index: 2;
  position: absolute;
}
::v-deep(.van-calendar__selected-day::after) {
    
    
  background-color: #fff !important;
}
::v-deep(.van-calendar__header-subtitle) {
    
    
  display: none;
}
::v-deep(.van-calendar__weekday) {
    
    
  color: rgba($color: #000000, $alpha: 0.5);
}
::v-deep(.van-calendar__weekday::before) {
    
    
  content: "周";
  color: rgba($color: #000000, $alpha: 0.5);
}
//有数据日期加点
::v-deep(.addDot) {
    
    
  position: relative;
}
::v-deep(.addDot::after) {
    
    
  position: absolute;
  content: "";
  width: 12px;
  height: 12px;
  top: 26Px;
  left: 45px;
  border-radius: 50%;
  background-color: #0084ff;
}
//当天日期
::v-deep(.calendarToday) {
    
    
  position: relative;
  color: #fff;
  // font-size: 0;
  // z-index: 1;
}
::v-deep(.calendarToday::before) {
    
    
  width: 35Px;
  height: 35Px;
  line-height: 35Px;
  position: absolute;
  top: 0;
  content: "今";
  text-align: center;
  font-size: 30px;
  border-radius: 50%;
  background-color: #ffae34;
  // z-index: -1;
}
//当天日期并且有数据
::v-deep(.addDot_calendarToday::after) {
    
    
  position: absolute;
  content: "";
  width: 12px;
  height: 12px;
  top: 26Px;
  left: 45px;
  border-radius: 50%;
  background-color: #fff;
  z-index: 4;
}
::v-deep(.addDot_calendarToday::before) {
    
    
  width: 35Px;
  height: 35Px;
  line-height: 35Px;
  position: absolute;
  top: 0;
  content: "今";
  text-align: center;
  font-size: 30px;
  border-radius: 50%;
  color: #fff;
  background-color: #ffae34;
}
//有数据并且被选中
::v-deep(.addDot_Select::after) {
    
    
  position: absolute;
  content: "";
  width: 12px;
  height: 12px;
  top: 26Px;
  left: 45px;
  border-radius: 50%;
  background-color: #fff;
  z-index: 3;
}
//被选中显示的今字
::v-deep(.calendarToday .van-calendar__selected-day) {
    
    
  font-size: 0;
}
::v-deep(.calendarToday .van-calendar__selected-day::before) {
    
    
  content: "今";
  z-index: 9;
  font-size: 30px;
  height: 35Px;
  line-height: 35Px;
}
::v-deep(.addDot_calendarToday .van-calendar__selected-day) {
    
    
  font-size: 0;
}
::v-deep(.addDot_calendarToday .van-calendar__selected-day::before) {
    
    
  content: "今";
  z-index: 9;
  font-size: 30px;
  height: 35Px;
  line-height: 35Px;
}
</style>

<style lang="scss">
.toast-c {
    
    
  width: 450px;
  height: 60px;
  padding: 22px 40px;
  min-height: 60px;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  .van-toast__icon {
    
    
    font-size: 48px;
    margin-right: 10px;
  }
  .van-toast__text {
    
    
    font-size: 28px;
    margin-top: 0;
  }
}
</style>

Guess you like

Origin blog.csdn.net/weixin_46687032/article/details/126508816