實現的日曆效果圖
話不多說,上程式碼!
<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>