vue + moment.js 自己写日历

使用技术

vue + moment.js

最终效果

因为自身需求,所以周六周日被我隐藏了,周六周日的显示隐藏可以配置。
以下代码是按照有周六周日写的。
在这里插入图片描述

HTML 结构

此日历采用了ul li 的结构进行展示的,整个日历为一个ul,一行为一个li

<div>
	<el-row type="flex" justify="space-between" align="middle" class="calendar-head">
     <div class="month-btn" @click="prevFun">
       <i class="el-icon-arrow-left"></i>
     </div>
     <div class="date-text">{{ monthShow }}</div>
     <el-row type="flex" align="middle">
       <!-- <div class="today-btn" @click="backToday">Today</div> -->
       <div class="month-btn" @click="nextFun">
         <i class="el-icon-arrow-right"></i>
       </div>
     </el-row>
   </el-row>
   <ul class="calendar-box">
     <li class="week">
       <div v-for="(item, index) in weekName" :key="index" class="calendar-week">
        {{ item }}
       </div>
     </li>
     <li v-for="(obj, index) in initDate" :key="index">
		<div v-for="(item, i) in obj.week" :key="i" :style="current" :class="{ noshow: false }">
		  <span :class="item.class" @click="selectDate(item)">{{item.data}}</span>
		</div>
     </li>
   </ul>
</div>

CSS样式

.calendar-head {
    width: 90%;
    margin: 0 auto;
}
.date-text {
    font-size: 16px;
    font-weight: 600;
}
.month-btn {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	box-shadow: 0 0.25rem 0.75rem rgba(#003a7c, 0.16);
	text-align: center;
	line-height: 32px;
	cursor: pointer;
}
.calendar-box .week {
	display: flex;
    justify-content: space-around;
    margin-top: 24px;
}
.calendar-box .week div {
	width: 13%;
    height: 60px;
    border-radius: 4px;
    margin-bottom: 4px;
}
.calendar-box li div span {
	display: inline-block;
    position: relative;
    height: 100%;
    width: 100%;
    border-radius: 4px;
}
.calendar-week {
	text-align: center;
	line-height: 50px;
}
.current {
  background-color: #deecf9;
}
.prev,
.next {
  background-color: #f7f7f7;
}
.noshow {
	display: none;
}

日历计算逻辑

1、先了解下moment.js 库
它是专门用于日期处理的JavaScript库,对于日期格式化,日期计算是很方便。
安装方式: npm install moment --save
页面中直接使用: import moment from ‘moment’;
官网传送门:http://momentjs.cn/
本次日历用到的:
moment().daysInMonth(); // 获取当前月的天数
moment(‘11’).dayInMonth(); // 获取11月份的天数
moment().clone(); // 克隆moment,以防止影响原始的moment
moment().format(‘MM’); // 获取当前月份
moment().add(1, ‘month’) // 获取下一个月
moment().subtract(1,‘month’) // 获取上一个月
moment().startOf(‘month’).weekday(); //当前月第一天是星期几
2、 必须要知道的几个节点
- 当月的第一天是星期几
- 当月一共多少天 (是30 还是 31天)

3、代码

//一些变量声明
const initDate = ref([]);
const weekName = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
const monthShow = ref();
const today = moment();
// 当月多少天
const getMonthDays = (momentObj) => {
  return momentObj.daysInMonth();
};
// 当月第一天是周几
const getWeekDays = (momentObj) => {
   return momentObj.startOf('month').weekday();
};
// 日历日期
const setDate = (m) => {
	const monthData = ref([]);
	initDate.value = [];
	const curDays = getMonthDays(m);
	// 当月第一天是星期几
	const curWeek = getWeekDays(m.clone());
	// 定义一下上个月的总天数
	const upDays = ref(getMonthDays(m.clone().subtract(1, 'month')));
	const curMonth = m.format('MM');
	const curYear = m.format('YYYY');
	// 整个日历显示的天数   6行  一行七天  共42天 
	const calendarRow = ref(42);
	//日历上显示下个月的日期
	const nextFirstDate= ref(0);
	for (const i = ref(0); i.value < calendarRow.value; i.value++) {
		/** 此处是 i从0开始,小于当月第一天的星期数 
		    例如: 当月第一天是周三,那么curWeek = 3,
		      那周三之前的天数(周日-周二)都是属于上个月的。
		      假如upDays = 30,即上个月共30天,
		      那28 29 30 这三天都要显示到日历上。
		*/
		if(i.value < curWeek) {
			monthData.value.push({
				data: upDays.value,
				fullDate: '',
				class: 'prev'
			});
			upDays.value--;
		} else if (i.value >= curDays + curWeek) {
			  /**
			    大于当月总天数+当月第一天星期数,说明已经来到了下个月要显示的日期。
			    累加nextFirstDate变量,用于显示下个月的几个日期
			    例如: 当月31天,1号是星期三,来到这,
			    日历上已经显示了上个月的28 29 30号
			    以及当月的1-31号,一共31+3 = 34天了,当前日历显示42天
			    说明还有42-34= 8天要显示,这8天都是下个月的日期。
			  */
			  nextFirstDate.value++;
			  monthData.value.push({
		        data: nextFirstDate.value,
		        fullDate: '',
		        class: 'next'
		      });
		} else {
		   //当月要显示的日期
			monthData.value.push({
			   data: i.value - curWeek + 1,
			   fullDate: '',
			   class: 'current'
			});
			monthShow.value = m.format('MMM YYYY')
		}
	}
	
	// 以下是 用来处理日历数据结构的
	const row = monthData.value.length / 7;  // 计算日历有几行
	for ( const i = ref<number>(0); i.value < row; i.value++ ) {
		initDate.value.push({ week: [] });
	}
	const weekData = ref();
	const count = ref(0);
	const res = ref<any>([]);
	for (const i = ref(0),len = monthData.value.length; i.value < len; i.value < len; i.value += 7) {
		res.value.push(monthData.value.slice(i.value, i.value + 7));
		res.value[0].forEach((item: any) => {
			weekdata.value = moment(item.fullDate).format('dd');
			initDate.value[count.value].week.push({ ...item, week: weekdata.value });
		});
		count.value += 1;
		res.value = [];
	}
};

// 切换上一月
const preFun = () => {
	setDate(today.subtract(1, 'month'));
};
// 切换下一月
const nextFun = () => {
	setDate(today.add(1,'month'))
};

onMounted(() => {
	setDate(today);
})

4、说一下 日历的数据结构

这个日历的数据结构,是我自己根据需求来制定的。
结构如下:
  最外层数据,几行就有几个对象
  对象里面的week数组,一行有几个日期就有几个对象
 const initDate = [
   {
   	 week:[
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'},
   	 	{data: 1, fulldate: '2021-12-12', class:'current'}
   	 ]
   },
   {},
   {},
   {},
   {},
   {}
 ]

在这里插入图片描述

简述

代码里用了vue3.0 + typeScript 的写法,如果你是要在vue2.0中使用的话,建议参照 逻辑部分自行修改成2.0的写法,(所有变量声明放入data中,const声明的函数放入methods 中,去掉声明时带有的 :any 类型声明就差不多了)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值