实现的日历效果图
话不多说,上代码!
<template> <view class="page"> <safe-area></safe-area> <view class="calendar-wrapper"> <view class="calendar-toolbar"> <text class="prev" onclick="prevMonth">〈</text> <text class="current">{{ currentDateStr }}</text> <text class="next" onclick="nextMonth">〉</text> </view> <view class="calendar-week"> <text class="week-item" v-for="item of weekList" :key="item">{{ item }}</text> </view> <view class="calendar-inner"> <text class="calendar-item" v-for="(item, index) of calendarList" :key="index" :class="this.changestyle(item.disable,item.value)" onclick="selDate" :data-val="item.value" :data-status="item.disable" :data-num="item.date">{{ item.date }}</text> </view> </view> </view> </template> <script> export default { name: 'calendar', installed(){ this.setCurrent(); this.calendarCreator(); }, data() { return{ current:{}, weekList:['周日','周一','周二','周三','周四','周五','周六'], shareDate: new Date(), calendarList: [], seldate:'点击选择日期', selweek:'待定', } }, computed: { // 显示当前时间 currentDateStr() { let { year, month } = this.current; return `${year}年${this.pad(month + 1)}月`; } }, methods: { selDate (e){ // console.log(JSON.stringify(e.currentTarget.dataset.val)); let status = e.currentTarget.dataset.status; let num = e.currentTarget.dataset.num; if(status){ this.data.seldate = e.currentTarget.dataset.val; this.getWeek(); if(num>7){ this.prevMonth(); } else{ this.nextMonth(); } } else{ this.data.seldate = e.currentTarget.dataset.val; this.getWeek(); //重新加载一次日历 改变样式 this.calendarCreator(); } this.fire('clickDate', this.data.seldate); }, changestyle(status,date){ if(status){ return 'calendar-item-disabled'; } else{ if(date == this.data.seldate){ return 'calendar-item-checked'; } else{ return 'calendar-item'; } } }, // 判断当前月有多少天 getDaysByMonth(year, month) { // console.log("本月多少天:"+new Date(year, month + 1, 0).getDate()); return new Date(year, month + 1, 0).getDate(); }, getFirstDayByMonths(year, month) { // console.log("本月第一天周几:"+new Date(year, month, 1).getDay()); return new Date(year, month, 1).getDay(); }, getLastDayByMonth(year, month) { // console.log("本月最后一天周几:"+new Date(year, month + 1, 0).getDay()); return new Date(year, month + 1, 0).getDay(); }, // 对小于 10 的数字,前面补 0 pad(str) { return str < 10 ? `0${str}` : str; }, // 点击上一月 prevMonth() { this.current.month--; // 因为 month的变化 会超出 0-11 的范围, 所以需要重新计算 this.correctCurrent(); // 生成新日期 this.calendarCreator(); }, // 点击下一月 nextMonth() { this.current.month++; // 因为 month的变化 会超出 0-11 的范围, 所以需要重新计算 this.correctCurrent(); // 生成新日期 this.calendarCreator(); }, // 格式化时间,与主逻辑无关 stringify(year, month, date) { let str = [year, this.pad(month + 1), this.pad(date)].join('-'); return str; }, // 设置或初始化 current setCurrent(d = new Date()) { let year = d.getFullYear(); let month = d.getMonth(); let date = d.getDate(); this.current = { year, month, date } }, // 修正 current correctCurrent() { let { year, month, date } = this.data.current; let maxDate = this.getDaysByMonth(year, month); // 预防其他月跳转到2月,2月最多只有29天,没有30-31 date = Math.min(maxDate, date); let instance = new Date(year, month, date); this.setCurrent(instance); }, // 生成日期 calendarCreator() { // 一天有多少毫秒 const oneDayMS = 24 * 60 * 60 * 1000; let list = []; let { year, month } = this.data.current; // 当前月份第一天是星期几, 0-6 let firstDay = this.getFirstDayByMonths(year, month); // 填充多少天 let prefixDaysLen = firstDay === 0 ? 7 : firstDay; // 毫秒数 let begin = new Date(year, month, 1).getTime() - oneDayMS * prefixDaysLen; // 当前月份最后一天是星期几, 0-6 let lastDay = this.getLastDayByMonth(year, month); // 填充多少天, 和星期的排放顺序有关 let suffixDaysLen = lastDay === 0 ? 6 : 6 - lastDay; // 毫秒数 let end = new Date(year, month + 1, 0).getTime() + oneDayMS * suffixDaysLen; while (begin <= end) { // 享元模式,避免重复 new Date this.data.shareDate.setTime(begin); let year = this.data.shareDate.getFullYear(); let curMonth = this.data.shareDate.getMonth(); let date = this.data.shareDate.getDate(); list.push({ year: year, month: curMonth, date: date, disable: curMonth !== month, value: this.stringify(year, curMonth, date) }); begin += oneDayMS; } this.data.calendarList = list; // console.log(JSON.stringify(this.data.calendarList)); }, //获取选中日期的周几 getWeek(){ let index =new Date(this.data.seldate).getDay(); let weekArr = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五','星期六']; let week = weekArr[index]; this.data.selweek = week; }, } } </script> <style> .page { height: 100%; } .calendar-wrapper { margin: 10px 10px 0 10px; background-color:#3c40c6; border-top-left-radius: 10px; border-top-right-radius: 10px; max-height: 400px; } .calendar-toolbar { padding: 10px 10px; flex-flow: row nowrap; justify-content: space-between; align-items: center; border-bottom: 1px solid #fff; } .prev{ flex: 1; text-align: center; color: #fff; } .current { flex: 1; text-align: center; color: #fff; } .next{ flex: 1; text-align: center; color: #fff; } .calendar-week { padding: 5px 10px; flex-flow: row nowrap; justify-content: space-around; align-items: center; } .week-item { padding: 5px; font-weight: bolder; font-size: 12px; color: #fff; } .calendar-inner{ padding: 10px 10px; flex-flow: row wrap; justify-content: space-around; align-items: center; } .calendar-item { width:14%; font-weight: bolder; text-align: center; font-size: 15px; color: #fff; padding: 5px; background-color: #3c40c6; } .calendar-item-disabled { width:14%; font-weight: bolder; text-align: center; font-size: 15px; color: #999; } .calendar-item-checked { width:14%; font-weight: bolder; text-align: center; font-size: 15px; color: #000000; background-color: #ffffff; border-radius: 5px; } </style>
其他页面引用
<template> <view class="page"> <calendar onclickDate="getSelDate"></calendar> <view> <text>当前日期是</text> <text>{today}</text> </view> </view> </template> <script> import '../../components/calendar.stml' export default { name: 'test', apiready(){ }, data() { return{ today:'' } }, methods: { getSelDate(e){ console.log(JSON.stringify(e)); this.data.today = e.detail; api.toast({ msg:'当前选中日期是:'+e.detail }) } } } </script> <style> .page { height: 100%; } </style>
现在,APICloud 官方正在举办 AVM 组件的征集大赛,通过审核就能获得一定的奖金,大家感兴趣的也可以去围观一下。传送门:https://www.apicloud.com/activity2205