Loading... ##### 一、组件(components->calendar->calendar) ###### 1、wxml代码 ```html <!-- components/calendar/calendar.wxml --> <view class="month-picker"> <!-- 年月和切换按钮 --> <view class="picker-header"> <view class="header-left">{{currentYear}}年{{currentMonth+1}}月</view> <view class="header-right"> <view class="prev-btn {{isPrevDisabled ? 'disabled' : ''}}" bindtap="switchPrevMonth">◀</view> <view class="next-btn" bindtap="switchNextMonth">▶</view> </view> </view> <!-- 星期行 --> <view class="week-days"> <view class="week-day" wx:for="{{weekDays}}" wx:key="*this">{{item}}</view> </view> <!-- 日期行 --> <view class="days"> <view wx:for="{{days}}" wx:key="*this" class="day {{item.isCurrentMonth ? '' : 'other-month'}} {{item.isToday ? 'today' : ''}} {{item.isDisabled ? 'disabled' : ''}} {{selectedDate === item.date ? 'selected' : ''}}" bindtap="onSelectDay" data-date="{{item.date}}" data-day="{{item}}" > {{item.isView ? item.day : ''}} </view> </view> </view> ``` ###### 2、wxss代码 ```css /* components/calendar/calendar.wxss */ .month-picker { width: 100%; background-color: #fff; border-radius: 10rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); overflow: hidden; } .picker-header { display: flex; justify-content: space-between; align-items: center; padding: 20rpx 30rpx; border-bottom: 1rpx solid #eee; } .header-left { font-size: 32rpx; font-weight: bold; color: #333; } .header-right { display: flex; } .prev-btn, .next-btn { width: 60rpx; height: 60rpx; display: flex; justify-content: center; align-items: center; border-radius: 50%; margin-left: 20rpx; background-color: #f5f5f5; font-weight: bold; } .prev-btn.disabled, .next-btn.disabled { color: #ccc; background-color: #f9f9f9; } .week-days { display: flex; padding: 20rpx 0; border-bottom: 1rpx solid #eee; } .week-day { flex: 1; text-align: center; font-size: 28rpx; color: #666; } .days { display: flex; flex-wrap: wrap; } .day { width: calc(100% / 7); height: 80rpx; display: flex; justify-content: center; align-items: center; font-size: 28rpx; position: relative; z-index: 0; } .day.other-month { color: #ccc; } .day.disabled { color: #ccc; } .day.selected { color: #fff; } .day.selected::before { content: ''; box-sizing: border-box; padding: 25rpx 35rpx; position: absolute; z-index: -1; border-radius: 30rpx; background-color: #013d59; } ``` ###### 3、js ```js // components/calendar/calendar.js Component({ properties: { // 初始选中日期,格式为 YYYY-MM-DD value: { type: String, value: '', observer: function(newVal) { if (newVal) { this.setSelectedDate(newVal); } } } }, data: { currentYear: 0, // 当前显示的年 currentMonth: 0, // 当前显示的月(0-11) selectedDate: null, // 选中的日期 days: [], // 日历数据 weekDays: ['日', '一', '二', '三', '四', '五', '六'], isPrevDisabled: true // 上个月按钮是否禁用 }, lifetimes: { attached: function() { // 初始化当前日期 const today = new Date(); const year = today.getFullYear(); const month = today.getMonth(); // 设置初始状态 this.setData({ currentYear: year, currentMonth: month, selectedDate: this.properties.value || this.formatDate(today) }); // 生成日历 this.generateCalendar(year, month); } }, methods: { // 生成指定年月的日历数据 generateCalendar(year, month) { const days = []; const today = new Date(); const currentDate = today.getDate(); // 获取本月第一天 const firstDay = new Date(year, month, 1); // 获取本月最后一天 const lastDay = new Date(year, month + 1, 0); // 获取本月第一天是星期几(0是周日) const firstDayWeek = firstDay.getDay(); // 获取上个月的最后几天(用于填充日历第一行) const prevMonthLastDay = new Date(year, month, 0).getDate(); // 填充上个月的日期 for (let i = 0; i < firstDayWeek; i++) { const day = prevMonthLastDay - firstDayWeek + i + 1; days.push({ day: day, year: month === 0 ? year - 1 : year, month: month === 0 ? 11 : month - 1, isCurrentMonth: false, isToday: false, isDisabled: true, // 上个月的日期全部禁用 isView: false, // 是否显示上个月日期 date: this.formatDate(new Date(month === 0 ? year - 1 : year, month === 0 ? 11 : month - 1, day)) }); } // 填充本月的日期 for (let i = 1; i <= lastDay.getDate(); i++) { const date = new Date(year, month, i); const isToday = year === today.getFullYear() && month === today.getMonth() && i === currentDate; // 判断日期是否应该禁用(今天之前的日期) const isDisabled = date < new Date(today.getFullYear(), today.getMonth(), today.getDate()); days.push({ day: i, year: year, month: month, isCurrentMonth: true, isToday: isToday, isDisabled: isDisabled, isView: true, date: this.formatDate(date) }); } // 填充下个月的日期(补全日历最后一行) // const nextMonthDays = 42 - days.length; // 6行7列=42个格子 // for (let i = 1; i <= nextMonthDays; i++) { // days.push({ // day: i, // year: month === 11 ? year + 1 : year, // month: month === 11 ? 0 : month + 1, // isCurrentMonth: false, // isToday: false, // isDisabled: true, // 下个月的日期全部禁用 // date: this.formatDate(new Date(month === 11 ? year + 1 : year, month === 11 ? 0 : month + 1, i)) // }); // } // 检查上个月按钮是否应该禁用 const isPrevDisabled = this.isPrevMonthDisabled(year, month); this.setData({ days: days, isPrevDisabled: isPrevDisabled }); }, // 切换到上个月 switchPrevMonth() { if (this.data.isPrevDisabled) return; let newYear = this.data.currentYear; let newMonth = this.data.currentMonth - 1; if (newMonth < 0) { newYear--; newMonth = 11; } this.setData({ currentYear: newYear, currentMonth: newMonth }); this.generateCalendar(newYear, newMonth); }, // 切换到下个月 switchNextMonth() { let newYear = this.data.currentYear; let newMonth = this.data.currentMonth + 1; if (newMonth > 11) { newYear++; newMonth = 0; } this.setData({ currentYear: newYear, currentMonth: newMonth }); this.generateCalendar(newYear, newMonth); }, // 选择日期 onSelectDay(e) { const day = e.currentTarget.dataset.day; // 如果日期被禁用,则不处理 if (day.isDisabled) return; // 选中的日期为当前日期,则不处理 if(this.data.selectedDate === day.date) return; this.setData({ selectedDate: day.date }); // 触发选择事件 this.triggerEvent('change', { value: day.date }); }, // 检查上个月按钮是否应该禁用 isPrevMonthDisabled(year, month) { const today = new Date(); const currentYear = today.getFullYear(); const currentMonth = today.getMonth(); // 如果显示的月份是当前月份或更早,则禁用上个月按钮 return year < currentYear || (year === currentYear && month <= currentMonth); }, // 设置选中的日期 setSelectedDate(dateStr) { const date = new Date(dateStr); const year = date.getFullYear(); const month = date.getMonth(); const day = date.getDate(); // 如果选中的日期不在当前显示的月份,切换到对应月份 if (year !== this.data.currentYear || month !== this.data.currentMonth) { this.setData({ currentYear: year, currentMonth: month }); this.generateCalendar(year, month); } this.setData({ selectedDate: dateStr }); }, // 格式化日期为 YYYY-MM-DD formatDate(date) { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return `${year}-${month}-${day}`; } } }); ``` ##### 二、页面调用 ###### 1、json代码 ```jso { "usingComponents": { "calendar": "/components/calendar/calendar" } } ``` ###### 2、wxml代码 ```html <calendar value="{{selectedDate}}" bind:change="onDateChange" /> ``` ###### 3、js代码 ```js Page({ /** * 页面的初始数据 */ data: { selectedDate: '' // 初始选中的日期 }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { // 设置默认选中今天 const today = new Date(); const todayStr = `${today.getFullYear()}-${(today.getMonth()+1).toString().padStart(2, '0')}-${today.getDate().toString().padStart(2, '0')}`; this.setData({ selectedDate: todayStr }); }, // 日期选择 onDateChange(e) { // 处理日期选择事件 console.log('选择的日期:', e.detail.value); this.setData({ selectedDate: e.detail.value }); } }) ``` ##### 三、效果图  最后修改:2025 年 09 月 05 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏