【vue2】一个基于vant改造的记账日历组件

584 阅读2分钟

vant里的组件没有提供上下月切换的效果,故自己仿造实现了一个

效果:

<template>
    <div>
        <div class="title-wrap">
            <div @click="preMonth">
                <img
                    src="../../assets/images/home/calendar/leftArrowSolid.png"
                    alt="上月"
                />
            </div>
            <div class="title" @click="show=true">{{ year }}年{{ month }}月</div>
            <div @click="nextMonth">
                <img
                    src="../../assets/images/home/calendar/rightArrowSolid.png"
                    alt="下月"
                />
            </div>
        </div>
        <div class="weekdays">
            <span class="weekday"></span>
            <span class="weekday"></span>
            <span class="weekday"></span>
            <span class="weekday"></span>
            <span class="weekday"></span>
            <span class="weekday"></span>
            <span class="weekday"></span>
        </div>
        <div class="body">
            <div class="month">
                <div role="grid" class="days">
                    <div class="month-mark" style="">{{ Number(month) }}</div>
                    <div v-for="item in daysList" :key="item.day" :class="{day:true,active:item.active,today:item.today}"
                    :style="item.day===1 && {'margin-left': left + '%'}">
                        {{ item.day }}
                    </div>
                </div>
            </div>
        </div>
        <van-popup v-model="show" round position="bottom">
            <van-picker
                title="选择月份"
                show-toolbar
                :columns="columns"
                @confirm="onConfirm"
                @cancel="onCancel"
            />
        </van-popup>
    </div>
</template>
<script>
import computeWeek from "../../assets/js/helper/computeWeek";
import getDaysInMonth from "../../assets/js/helper/getDaysInMonth";
import { startYear, fullYear, fullMonth } from "../../assets/js/helper/yearMonth";
import {isRecordedDay} from '../../api/myCalendar';//该天是否有记账记录
import isToday from '../../assets/js/utils/isToday';
import Vue from 'vue';

import {Popup, Picker} from 'vant';
Vue.use(Popup);
Vue.use(Picker);
export default {
    data() {
        return {
            year: 2021,
            month: 1,
            show:false
        };
    },
    mounted() {
        let date = new Date();
        this.year = date.getFullYear();
        this.month = fullMonth[date.getMonth()];
    },
    computed: {
        left() {
            let week = computeWeek(this.year, Number(this.month));
            return ((week / 7) * 100).toFixed(4);
        },
        daysList(){
            let days = getDaysInMonth(this.year, Number(this.month));
            let list = [];
            for (let i = 1; i <= days; i++) {
                list.push({day:i,active:isRecordedDay(this.year,Number(this.month),i),today:isToday(this.year,Number(this.month),i)});
            }
            return list;
        },
        columns() {
            return [
                // 第一列
                {
                    values: fullYear,
                    defaultIndex: this.year - startYear,
                },
                // 第二列
                {
                    values: fullMonth,
                    defaultIndex: this.month - 1,
                },
            ]
        }
    },
    methods: {
        nextMonth() {
            let month = Number(this.month);
            if (month + 1 <= 12) {
                this.month = fullMonth[month];
            } else {
                this.month = fullMonth[month - 12];
                this.year += 1;
            }
        },
        preMonth() {
            let month = Number(this.month);
            if (month - 1 >= 1) {
                this.month = fullMonth[month - 2];
            } else {
                this.month = fullMonth[month + 10];
                this.year -= 1;
            }
        },
        onConfirm(value, index) {
            this.year = value[0];
            this.month = value[1];
            this.show = false;
        },
        onCancel() {
            this.show = false;
        },
    },
};
</script>
<style scoped>
.title-wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 0.2rem;
}
.title-wrap img {
    width: 0.4rem;
    height: 0.4rem;
}
.title {
    height: 0.88rem;
    font-weight: 500;
    line-height: 0.88rem;
    text-align: center;
    font-size: 0.28rem;
}
.weekdays {
    font-size: 0.32rem;
    display: flex;
}
.weekdays .weekday {
    flex: 1;
    font-size: 12px;
    line-height: 30px;
    text-align: center;
    border-bottom: 0.1rem solid #efefef;
}
.body {
    font-size: 0.32rem;
    -webkit-box-flex: 1;
    flex: 1;
    overflow: auto;
}

.days {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    user-select: none;
}

.month-mark {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 0;
    color: rgba(242, 243, 245, 0.8);
    font-size: 3.23rem;
    transform: translate(-50%, -50%);
    pointer-events: none;
}

.day {
    display: flex;
    -webkit-box-align: center;
    align-items: center;
    -webkit-box-pack: center;
    justify-content: center;
    text-align: center;
    position: relative;
    width: 14.285%;
    height: 1.28rem;
    font-size: 0.32rem;
    position: relative;
}

.day.active{
    background-image: url("../../assets/images/home/calendar/gou.png");
    background-size: 50%;
    background-repeat: no-repeat;
    background-position: center;
}

.day.today{
    background-color: rgba(0,1,0,0.08);
}

.day.today::after{
    content: '今天';
    font-size: 0.15rem;
    color: red;
    position:absolute;
    right: 0;
    top: 0.1rem;
}

.selected-day {
    cursor: pointer;
    display: flex;
    -webkit-box-align: center;
    align-items: center;
    -webkit-box-pack: center;
    justify-content: center;
    text-align: center;
    width: 1.08rem;
    height: 1.08rem;
    color: #fff;
    border-radius: 4px;
    background: rgb(0, 150, 136);
}

相关js文件

  1. computeWeek.js
/**
 * 计算year年month月的1号是星期几(0,周日),(1,周一)...
 * ->蔡勒(Zeller)公bai式
 * @param {*} year 
 * @param {*} month 
 */
function computeWeek(year, month, day = 1) {
    if(month<3){
        month += 12;
        year -= 1;
    }
    const c = Math.floor(year / 100);
    const y = year - c * 100;
    let week = y + Math.floor(c / 4) - 2 * c + Math.floor( y / 4) + Math.floor(13 * (month + 1) / 5) + day - 1;
    while (week < 0) {
        week += 7;
    }
    week %= 7;
    return week;
}

export default computeWeek;

2.getDaysInMonth.js

/**
 * 给定年月判断有几天
 * @param {*} year 
 * @param {*} month 
 */
export default function getDaysInMonth(year,month){
    return new Date(year, month, 0).getDate()
}

3.yearMonth.js

let startYear = 1900;
let endYear = 2100;
let fullYear = [];
let fullMonth = ['01','02','03','04','05','06','07','08','09','10','11','12'];
const fullWeek=["天","一","二","三","四","五","六"]
for(let i=startYear;i<=endYear;i++){
    fullYear.push(i);
}

export {startYear, fullYear, fullMonth, fullWeek}
  1. isToday.js
export default function isToday(year,month,day){
    const date = new Date();
    return year==date.getFullYear() && month==date.getMonth()+1 && day==date.getDate()
}