微信小程序校历组件

微信小程序校历组件

校历组件,可以作为校园小程序的插件,如果觉得不错,点个star吧 😃
Github: https://github.com/WindrunnerMax/SCalendar
山科小站小程序: https://github.com/WindrunnerMax/SHST

效果图#

在这里插入图片描述

使用#

导入微信开发者工具即可测试DEMO

Copy
<!-- 参数说明 --> <calendar term="2019-2020-2" termStart="2020-02-10" weekCount="29" vacationStart="24"></calendar> <!-- term: 当前学期 termStart: 开学日期 weekCount: 学期总周次 vacationStart: 假期开始周次 --> <!-- 注意: 所有填写日期需符合 yyyy-MM-dd 格式,例如 2020-03-01 而不是 2020-3-1 -->

实现#

引用工具类#

这是我的小程序( 山科小站 )写好的时间操作工具类,在组件中引用此工具类

Copy
/** * yyyy年 MM月 dd日 hh1~12小时制(1-12) HH24小时制(0-23) mm分 ss秒 S毫秒 K周 */ const formatDate = (fmt = "yyyy-MM-dd", date = new Date()) => { var week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]; var o = { "M+": date.getMonth() + 1, //月份 "d+": date.getDate(), //日 "h+": date.getHours(), //小时 "m+": date.getMinutes(), //分 "s+": date.getSeconds(), //秒 "q+": Math.floor((date.getMonth() + 3) / 3), //季度 "S": date.getMilliseconds(), //毫秒 "K": week[date.getDay()] }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) { if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); } return fmt; } /** * 拓展Date原型 */ const extDate = () => { Date.prototype.addDate = function (years = 0, months = 0, days = 0) { if (days !== 0) this.setDate(this.getDate() + days); if (months !== 0) this.setMonth(this.getMonth() + months); if (years !== 0) this.setFullYear(this.getFullYear() + years); } } /** * 计算日期差 */ const dateDiff = (startDateString, endDateString) => { var separator = "-"; //日期分隔符 var startDates = startDateString.split(separator); var endDates = endDateString.split(separator); var startDate = new Date(startDates[0], startDates[1] - 1, startDates[2]); var endDate = new Date(endDates[0], endDates[1] - 1, endDates[2]); var diff = parseInt((endDate - startDate) / 1000 / 60 / 60 / 24); //把相差的毫秒数转换为天数 return diff; } module.exports = { formatDate: formatDate, extDate: extDate, dateDiff: dateDiff }

JS逻辑#

首先得根据年月将本月的日历打印出来,使用util.formatDate("yyyy-MM-01", date)获取本月的1号的Data对象,然后计算他是本周的周几,使用Date.addDate()将日期转到1号所在的那周的周一,就是本月日历要打印的第一天,由于校历一般是周一作为一周的开始,所以需要稍微处理一下,不能直接减掉周次来将Date对象指向打印日历的第一天。
由于每月的日历最多是五个周,所以我们直接打印五个周的时间即可,使用Date.addDate()将日期一天一天累加,并将数据保存即可。
对于日期的样式,我是用了相对比较简单的办法,通过if判断日期来给予其特定的样式,我是将不同的class拼接为字符串赋值到unitObj上的,对于显示的颜色等,通过css的优先级控制,单元样式继承于容器,对于需要特定现实的样式提供一个detach字段保存。
跳转日期则直接获取时间来拼接月份然后调用日历月份处理方法即可。

Copy
const util = require("calendarUtil.js"); const date = new Date(); Component({ properties: { term: { type: String, value: '2019-2020-2', }, termStart: { type: String, value: '2020-02-10', }, weekCount: { type: Number, value: 29 }, vacationStart: { type: Number, value: 24 } }, data: { calendarData: [], vacationDateDiff: 0, vacationStartDate: "", curMonth: util.formatDate("MM", date), curYear: util.formatDate("yyyy", date), today: util.formatDate(undefined, date) }, created: function () { util.extDate(); }, ready: function () { this.calcVacation(); this.redayForDate(date); }, methods: { jumpDate: function(e){ var d = new Date(e.currentTarget.dataset.d); this.data.curMonth = util.formatDate("MM", d); this.data.curYear = util.formatDate("yyyy", d); this.redayForDate(d); this.setData({ curMonth: this.data.curMonth, curYear: this.data.curYear, }) }, switchMonth:function(e){ var d = new Date(this.data.curYear+"-"+this.data.curMonth+"-01"); var s = e.currentTarget.dataset.s; if (s === "l") d.addDate(0,-1); else d.addDate(0,1); this.data.curMonth = util.formatDate("MM", d); this.data.curYear = util.formatDate("yyyy", d); this.redayForDate(d); this.setData({ curMonth: this.data.curMonth, curYear: this.data.curYear, }) }, redayForDate: function(date){ var curMonthDay = util.formatDate("yyyy-MM-01", date); var monthStart = new Date(curMonthDay); var monthStartWeekDay = monthStart.getDay(); monthStartWeekDay = monthStartWeekDay === 0 ? 7 : monthStartWeekDay; var calendarStart = monthStart; calendarStart.addDate(0, 0, -(monthStartWeekDay - 1)); this.showCalendar(calendarStart); }, showCalendar: function (start) { var showArr = []; for (let i = 0; i < 6; ++i) { let innerArr = []; let week = 0; for (let k = 0; k < 7; ++k) { let unitDate = util.formatDate("yyyy-MM-dd", start); if (k === 0) { week = parseInt((util.dateDiff(this.data.termStart, unitDate) / 7)) + 1; week = week > 0 ? week : 0; innerArr.push({ day: week, color: "week ", type: "周次", detach:"" }) } let unitObj = { day: unitDate.split("-")[2], color: "notCurMonth ", type: "--", detach: ""}; if (util.formatDate("MM", start) === this.data.curMonth) unitObj.color = "curMonth "; if (unitDate === this.data.today) unitObj.color = "today "; if (unitDate === this.data.termStart) unitObj.color = "termStart "; if (unitDate === this.data.vacationStartDate) unitObj.color = "vacationStart "; if (k === 5 || k === 6) { unitObj.type = "周末"; unitObj.color += "weekend "; } else if (week && week < this.data.weekCount) { var tmpColor = "classes "; unitObj.type = "教学"; unitObj.detach = "cdetach"; if (week >= this.data.vacationStart) { unitObj.type = "假期"; tmpColor = "vacation "; unitObj.detach=""; } unitObj.color += tmpColor; } innerArr.push(unitObj); start.addDate(0, 0, 1); } showArr.push(innerArr); } this.setData({ calendarData: showArr }) }, calcVacation: function () { var d = new Date(this.data.termStart); d.addDate(0, 0, (this.data.vacationStart - 1) * 7); var vacationStartDate = util.formatDate(undefined, d); this.setData({ vacationStartDate: vacationStartDate, vacationDateDiff: util.dateDiff(this.data.today, vacationStartDate) }) } } })

wxml视图#

视图就是普通的使用循环建立日历

Copy
<view class="card"> <view class="y-CenterCon head"> <view class="y-CenterCon"> <view class="arrow-left" bindtap="switchMonth" data-s="l"></view> <view class="showDate">{{curYear}}年 {{curMonth}}月</view> <view class="arrow-right" bindtap="switchMonth" data-s="r"></view> </view> <view class="y-CenterCon"> <view class="opt y-CenterCon x-CenterCon" style="background-color: #1E9FFF;" bindtap="jumpDate" data-d="{{today}}"></view> <view class="opt y-CenterCon x-CenterCon" style="background-color: #FF6347;" bindtap="jumpDate" data-d="{{termStart}}"></view> <view class="opt y-CenterCon x-CenterCon" style="background-color: #3CB371;" bindtap="jumpDate" data-d="{{vacationStartDate}}"></view> </view> </view> <view> <view class="y-CenterCon line"> <view wx:for='{{["周","一","二","三","四","五","六","日"]}}' wx:key="{{index}}" class="unit">{{item}}</view> </view> <view wx:for="{{calendarData}}" wx:key="{{index}}" class="line"> <view wx:for="{{item}}" wx:for-item="innerItem" wx:for-index="innerIndex" wx:key="{{innerIndex}}"> <view class="unitCon {{innerItem.color}}"> <view class="unit u">{{innerItem.day}}</view> <view class="x-CenterCon intro {{innerItem.detach}}">{{innerItem.type}}</view> </view> </view> </view> </view> </view> <view class="card y-CenterCon info"> <view style="width: 40%;"> <view class="a-dot" style="background: #3CB371;"></view> <view >学期:{{term}}</view> </view> <view style="width: 24%;"> <view class="a-dot" style="background: #9F8BEC;"></view> <view>周次:{{weekCount}}</view> </view> <view style="width: 36%;"> <view class="a-dot" style="background: #FF6347;"></view> <view >开学:{{termStart}}</view> </view> </view> <view class="card y-CenterCon info"> <view style="width: 40%;"> <view class="a-dot" style="background: #3CB371;"></view> <view >假期:{{vacationStartDate}}</view> </view> <view style="width: 24%;"> <view class="a-dot" style="background: #9F8BEC;"></view> <view>周次:{{vacationStart}}</view> </view> <view style="width: 36%;"> <view class="a-dot" style="background: #FF6347;"></view> <view >距假期:{{vacationDateDiff}}天</view> </view> </view>

wxss样式#

多使用flex布局,通过样式的优先级来控制颜色的覆盖,即可控制不同日期的颜色

Copy
page{ margin: 0; font-family: Arial, Helvetica, 'STHeiti STXihei', 'Microsoft YaHei', Tohoma, sans-serif; padding: 10px; box-sizing: border-box; font-size: 13px; background-color: #F8F8F8; } .card{ padding: 10px; background: #fff; margin-bottom: 10px; box-sizing: border-box; } .head{ justify-content: space-between; margin: 5px 5px 5px 10px; } .showDate{ margin: 10px 20px; font-weight: bold; } .opt{ width: 20px; line-height: 20px; padding: 4px; margin: 0 10px; color: #fff; background-color: #9F8BEC; border-radius: 30px; } .line{ display: flex; justify-content: space-around; align-content: center; margin: 10px 0; } .unitCon{ color: #333; } .unitCon view{ color: inherit; } .unit{ line-height: 25px; width: 25px; margin: 2.5px; display: flex; justify-content: center; align-items: center; } .notCurMonth{ color: #ddd !important; } .today > .u,.termStart > .u,.vacationStart > .u{ color: #fff !important; border-radius: 30px; background: #1E9FFF; } .termStart > .u{ background: #FF6347; } .vacationStart > .u{ background: #3CB371; } .week{ color:#9F8BEC; } .intro{ font-size: 11px; } .curMonth > .cdetach{ color: #999; } .weekend,.vacation{ color: #3CB371; } .x-CenterCon { display: flex; justify-content: center; } .y-CenterCon { display: flex; align-items: center; } .a-full{ flex: 1; } .arrow-left,.arrow-right{ width: 25px; height: 25px; background-size: 25px 25px; background-repeat: no-repeat; background-image: url("data:image/svg+xml,%3C?xml version='1.0' standalone='no'?%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg t='1583569368665' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='1602' xmlns:xlink='http://www.w3.org/1999/xlink' width='200' height='200'%3E%3Cdefs%3E%3Cstyle type='text/css'%3E%3C/style%3E%3C/defs%3E%3Cpath d='M641.28 278.613333l-45.226667-45.226666-278.634666 278.762666 278.613333 278.485334 45.248-45.269334-233.365333-233.237333z' p-id='1603' fill='%238a8a8a'%3E%3C/path%3E%3C/svg%3E"); } .arrow-right{ transform:rotate(180deg); } .a-hr { display: block; height: 1px; background: #EEEEEE; border: none; margin: 10px 5px; } .a-dot { width: 8px; height: 8px; border-radius: 8px; background-color: #1E9FFF; margin-right: 5px; } .a-dot + view{ margin-right: 5px; } .info view{ display: flex; align-items: center; }
posted @   WindRunnerMax  阅读(768)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
CONTENTS