Use scenario description:
1. Display the date data of a single month, click to switch the month data
2. Click the date to close the calendar (display a week), and then click to expand the calendar (display the entire month)
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.
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>