广告位联系
返回顶部
分享到

小程序实现日历打卡功能的教程

JavaScript 来源:互联网 作者:佚名 发布时间:2022-08-28 20:39:24 人浏览
摘要

一、效果图展示 老惯例,先上效果图 二、实现思路 1、日历展示 例如下图中: 2021月7月打卡日历页面,共35个日期数据,上月残余4天+本月31天; 2021月6月打卡日历页面,共35个日期数据

一、效果图展示

老惯例,先上效果图

二、实现思路

1、日历展示

例如下图中:

2021月7月打卡日历页面,共35个日期数据,上月残余4天+本月31天;

2021月6月打卡日历页面,共35个日期数据,上月残余2天+本月30天+下月残余3天;

2021月5月打卡日历页面,共42个日期数据,上月残余6天+本月31天+下月残余5天。

【结论】打卡日历页面存在展示35个或42个日期数据的情况,35个或42个日期数据=当前显示月所有日期数据+上月残余尾部日期+下月残余头部日期。

计算出每个月的日期天数,获取本月1号是周几,上月残余天数=本月1号的星期X的X数(比如,2021年7月1日是星期四,则上月残余4天),假设 a=35-本月天数-上月残余天数。如果a>=0,则下月残余天数=a;如果a<0,则下月残余天数=7+a (比如2021年5月,35-37=-2;7+(-2)=5)

2、打卡功能

打卡实现的功能:可打卡的日期为今日日期或今日日期之前未打卡过的日期。

如图:今日日期为绿色圆形背景,当前点击日期为橙色圆形背景;可打卡时,打卡按钮背景为蓝色,不可打卡时,打卡背景为灰色;√ 代表已打卡。

通过数据库查询当前已打卡的数据,已打卡的数据需要设置打卡按钮禁用标志。打卡按钮禁用的情况(1)页面初始化时,未点击任何日期(2)当前点击的日期在今天之后(3)当前日期在今天之前但已打卡。

点击打卡,记录打卡日期并保存至数据库。

三、代码

1、数据库数据

2、日历组件

【calendar.wxml】

代码里使用了WXS页内脚本,渲染“已打卡”的标志(√)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

<view class="calendar">

  <view class='tit'>

    <view class='pre' bindtap='gotoPreMonth'>{{'《'}}</view>

    <view class='current'>{{currentYear}}年{{currentMonth}}月</view>

    <view class='next' bindtap='gotoNextMonth'>{{'》'}}</view>

  </view>

  <view class='w100P showData'>

    <view class="week" style='color: #999'>日</view>

    <view class="week">一</view>

    <view class="week">二</view>

    <view class="week">三</view>

    <view class="week">四</view>

    <view class="week">五</view>

    <view class="week" style='color: #999'>六</view>

  </view>

  <view class='content'>

    <view wx:for="{{allArr}}" wx:key="index" class='itemData' data-current="{{item.month == 'current' ? '1' : '0'}}"

      data-day='{{item.date}}' bindtap='clickDate'>

      <view class="{{item.month == 'current' ? '' : 'gray'}}"

        style="height:44px;width:44px;line-height:30px;{{nowYear==currentYear&&currentMonth==nowMonth&&item.date==nowDate?'color:#fff;background:#33D4C5;border-radius:100px':''}};{{item.month == 'current'&&selectedYear==currentYear&&selectedMonth==currentMonth&&item.date==selectedDate?'color:#fff;background:orange;border-radius:100px':''}} ">

        {{item.date}}

        <view>

          <icon wx:if="{{item.month == 'current'&&dataProcess.filterDate(currentPunchCardDate,item.date)}}" class="icon" color="#F44336" type="success_no_circle" size="15"></icon>

        </view>

      </view>

    </view>

  </view>

  <view class="btn-wrapper" bindtap="gotoToday">

    <button class="btn">回今天</button>

  </view>

  <!-- wxs页面内脚本,在渲染层做数据处理 -->

  <wxs module="dataProcess">

  function filterDate(currentPunchCardDate,date){

    if(currentPunchCardDate.indexOf(date)!==-1){

      return true

  }

  }

  module.exports={

    filterDate:filterDate

  }

  </wxs>

</view>

【calendar.wxss】

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

.calendar {

  width: 100%;

  background: #fff;

}

  

.pre,

.next {

  color: #33D4C5;

  text-align: center;

  line-height: 20px;

}

  

.calendar .tit {

  display: flex;

  justify-content: center;

  align-items: center;

  padding: 40rpx 0;

  

}

  

.current {

  font-size: 32rpx;

  color: #2A2A2A;

}

  

.calendar .tit .current {

  margin: 0 60rpx;

}

  

.showData {

  display: flex;

  justify-content: center;

  align-items: center;

  box-sizing: border-box;

  padding-left: 25rpx;

  padding-right: 25rpx;

}

  

.showData .week {

  width: 14%;

  height: 70rpx;

  line-height: 70rpx;

  text-align: center;

  flex-shrink: 0;

  font-size: 30rpx;

  color: #2A2A2A;

}

  

.calendar .content {

  display: flex;

  flex-wrap: wrap;

  box-sizing: border-box;

  padding-left: 25rpx;

  padding-right: 25rpx;

}

  

.calendar .content .itemData {

  width: 14.2%;

  height: 90rpx;

  line-height: 90rpx;

  flex-shrink: 0;

  font-size: 30rpx;

  color: #2A2A2A;

  text-align: center;

  display: flex;

  align-items: center;

  justify-content: center;

}

  

.calendar .content .icon {

  position: relative;

  top: -25rpx;

}

  

.calendar .content .gray {

  color: #999;

}

  

.currentSelected {

  color: #fff;

  background: #1CA2FC;

  border-radius: 100px;

}

  

.calendar .btn-wrapper {

  text-align: right;

  background-color: #fff;

  width: 100%;

  padding-bottom: 10rpx;

}

  

.calendar .btn-wrapper .btn {

  border: 1px solid #33D4C5;

  padding: 5rpx;

  width: 95rpx;

  font-size: 21rpx;

  color: #33D4C5;

  border-radius: 20rpx;

  margin-bottom: 15rpx;

  position: relative;

  left: calc(50% - 100rpx);

}

【calendar.js】

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

Component({

  /**

   * 组件的属性列表

   */

  

  properties: {

    currentPunchCardDate: {

      type: Array,

      value: []

    },

    currentYear: { // 当前页面显示的年

      type: Number,

      value: new Date().getFullYear()

    },

    currentMonth: { // 当前页面显示的年月

      type: Number,

      value: new Date().getMonth() + 1

    },

    nowYear: { // 当前年

      type: Number,

      value: new Date().getFullYear()

    },

    nowMonth: { // 当前月

      type: Number,

      value: new Date().getMonth() + 1

    },

    nowDate: { // 当前日

      type: Number,

      value: new Date().getDate()

    },

  

  },

  

  /**

   * 组件的初始数据

   */

  data: {

    currentMonthDateLen: 0, // 当月天数

    preMonthDateLen: 0, // 当月中,上月多余天数

    allArr: [], // 35个或42个日期数据=当前显示月所有日期数据+上月残余尾部日期+下月残余头部日期

    nowDate: null,

    selectedDate: null, //当前选择日期

    selectedMonth: null, //当前选择月

    selectedYear: null, //当前选择年

  },

  // 用observers监听properties的属性值

  observers: {

    'currentPunchCardDate': function (val) {

      console.log(val)

  

    }

  },

  // 在组件实例刚刚被创建时执行

  created() {},

  // 在组件实例进入页面节点树时执行

  ready() {

    this.getAllArr()

  },

  /**

   * 组件的方法列表

   */

  methods: {

    // 获取某年某月天数:下个月1日-本月1日 

    getDateLen(year, month) {

      let actualMonth = month - 1;

      let timeDistance = new Date(year, month) - new Date(year, actualMonth);

      return timeDistance / (1000 * 60 * 60 * 24);

    },

    // 获取某月1号是周几

    getFirstDateWeek(year, month) {

      // 0-6,0代表周天

      return new Date(year, month - 1, 1).getDay()

    },

    // 上月

    preMonth(year, month) {

      if (month == 1) {

        return {

          year: --year,

          month: 12

        }

      } else {

        return {

          year: year,

          month: --month

        }

      }

    },

    // 下月

    nextMonth(year, month) {

      if (month == 12) {

        return {

          year: ++year,

          month: 1

        }

      } else {

        return {

          year: year,

          month: ++month

        }

      }

    },

    // 获取当月数据,返回数组

    getCurrentArr() {

      let currentMonthDateLen = this.getDateLen(this.data.currentYear, this.data.currentMonth) // 获取当月天数

      let currentMonthDateArr = [] // 定义空数组

      if (currentMonthDateLen > 0) {

        for (let i = 1; i <= currentMonthDateLen; i++) {

          currentMonthDateArr.push({

            month: 'current', // 只是为了增加标识,区分上下月

            date: i

          })

        }

      }

      this.setData({

        currentMonthDateLen

      })

      return currentMonthDateArr

    },

    // 获取当月中,上月多余的日期数据,返回数组

    getPreArr() {

      let preMonthDateLen = this.getFirstDateWeek(this.data.currentYear, this.data.currentMonth) // 当月1号是周几 == 上月残余天数)

      console.log("preMonthDateLen=", preMonthDateLen);

      let preMonthDateArr = [] // 定义空数组

      if (preMonthDateLen > 0) {

        let {

          year,

          month

        } = this.preMonth(this.data.currentYear, this.data.currentMonth) // 获取上月 年、月

        let date = this.getDateLen(year, month) // 获取上月天数

        for (let i = 0; i < preMonthDateLen; i++) {

          preMonthDateArr.unshift({ // 尾部追加

            month: 'pre', // 只是为了增加标识,区分当、下月

            date: date

          })

          date--

        }

      }

      this.setData({

        preMonthDateLen

      })

      return preMonthDateArr

    },

    // 获取当月中,下月多余的日期数据,返回数组

    getNextArr() {

      let nextMonthDateLen = 35 - this.data.preMonthDateLen - this.data.currentMonthDateLen // 下月多余天数

      console.log(" nextMonthDateLen=", nextMonthDateLen);

      let nextMonthDateArr = [] // 定义空数组

      if (nextMonthDateLen > 0) {

        for (let i = 1; i <= nextMonthDateLen; i++) {

          nextMonthDateArr.push({

            month: 'next', // 只是为了增加标识,区分当、上月

            date: i

          })

        }

      } else if (nextMonthDateLen < 0) {

        for (let i = 1; i <= (7 + nextMonthDateLen); i++) {

          nextMonthDateArr.push({

            month: 'next', // 只是为了增加标识,区分当、上月

            date: i

          })

        }

  

      }

      return nextMonthDateArr

    },

    // 整合当月所有日期数据=上月残余+本月+下月多余

    getAllArr() {

      let preArr = this.getPreArr()

      let currentArr = this.getCurrentArr()

      let nextArr = this.getNextArr()

      let allArr = [...preArr, ...currentArr, ...nextArr]

      this.setData({

        allArr

      })

      let sendObj = {

        currentYear: this.data.currentYear,

        currentMonth: this.data.currentMonth,

        currentDate: this.data.selectedDate,

        allArr: this.data.allArr,

      }

      // 向父组件发送数据

      this.triggerEvent('sendObj', sendObj)

  

    },

    // 点击 上月

    gotoPreMonth() {

      let {

        year,

        month

      } = this.preMonth(this.data.currentYear, this.data.currentMonth)

      this.setData({

        currentYear: year,

        currentMonth: month,

      })

      this.getAllArr()

    },

    // 点击 下月

    gotoNextMonth() {

      let {

        year,

        month

      } = this.nextMonth(this.data.currentYear, this.data.currentMonth)

      this.setData({

        currentYear: year,

        currentMonth: month,

      })

      this.getAllArr()

    },

    // 点击日期

    clickDate(e) {

      var date = e.currentTarget.dataset.day;

      var current = e.currentTarget.dataset.current;

      if (current == 0) {

        if (date > 6) {

          // 点击上月日期--去上个月

          var {

            year,

            month

          } = this.preMonth(this.data.currentYear, this.data.currentMonth)

          this.gotoPreMonth()

        } else {

          // 点击下月

          var {

            year,

            month

          } = this.nextMonth(this.data.currentYear, this.data.currentMonth)

          this.gotoNextMonth()

        }

      } else {

        var year = this.data.currentYear;

        var month = this.data.currentMonth;

      }

      this.setData({

        selectedYear: year,

        selectedMonth: month,

        selectedDate: date,

      })

      console.log("当前选择日期", year, "-", month, "-", date);

      console.log(this.data.selectedDate);

      wx.nextTick(() => {

        this.getAllArr()

      })

  

    },

    // 回今天

    gotoToday() {

      this.setData({

        currentYear: this.data.nowYear,

        currentMonth: this.data.nowMonth,

      })

      this.getAllArr()

    }

  }

})

3、打卡及统计

【calendarCard.wxml】

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<view class="page-wrapper">

  <top-title toptitle="打卡日历" backImgFlag="true"></top-title>

  <calendar bind:sendObj="getObj" currentPunchCardDate="{{punchCardDateArr}}"></calendar>

  <view class="btn-wrapper">

    <button class="btn" type="primary" disabled="{{ disabledFlag}}" bindtap="punchCard">打 卡</button>

  </view>

  <view class="record-wrapper">

    <view class="title">

      <image class="img" src="{{icon}}"></image> {{name}}打卡统计

    </view>

    <view class="record">

      <view class="record-item">

        <view class="top"><text class="num">{{monthDays}}</text> 天</view>

        <view class="bottom">本月坚持天数</view>

      </view>

      <view class="record-item">

        <view class="top"><text class="num"> {{totalDays}}</text> 天</view>

        <view class="bottom">总共坚持天数</view>

      </view>

    </view>

  </view>

</view>

【calendarCard.wxss】

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

.page-wrapper {

  background-color: #fff;

  height: 100vh;

}

.page-wrapper .btn-wrapper .btn {

  width: 95vw;

  border-radius: 40rpx;

  height: 80rpx;

  font-size: 30rpx;

  background-color: #27d6f5;

  padding: 20rpx;

}

.page-wrapper .btn-wrapper .btn[disabled] {

  background-color: #e7e5e5;

}

.page-wrapper .record-wrapper {

  padding: 20rpx;

}

.page-wrapper .record-wrapper .title {

  color: #444;

  font-weight: bold;

}

.page-wrapper .record-wrapper .title .img {

  width: 60rpx;

  height: 60rpx;

  position: relative;

  top: 18rpx;

}

.page-wrapper .record-wrapper .record {

  display: flex;

  justify-content: space-around;

  margin-top: 20rpx;

}

.page-wrapper .record-wrapper .record .record-item {

  text-align: center;

  font-size: 24rpx;

  color: #a3a3a3;

}

.page-wrapper .record-wrapper .record .record-item .top {

  height: 80rpx;

  line-height: 80rpx;

  border-bottom: 1px solid #ececec;

  color: #333;

}

.page-wrapper .record-wrapper .record .record-item .top .num {

  font-size: 44rpx;

  font-weight: bold;

  color: #F44336;

}

【calendarCard.js】

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

// miniprogram/pages/punchCard/calendarCard/calendarCard.js

Page({

  

  /**

   * 页面的初始数据

   */

  data: {

    id: null,

    name: "",

    icon: "",

    disabledFlag: true,

    totalDays:0,

    monthDays:0,

    habitInfo: {},

    currentDate: null,

    currentMonth: null,

    currentYear: null,

    nowYear: new Date().getFullYear(),

    nowMonth: new Date().getMonth(),

    nowDate:new Date().getDate(),

    punchCardDateArr: [] //用于存放当月打卡日期-日

  

  },

  /**

   * 生命周期函数--监听页面加载

   */

  onLoad: function (options) {

    console.log(options);

    this.setData({

      id: options.id,

      name: options.name,

      icon: options.icon

    })

    var nowYear = new Date().getFullYear()

    var nowMonth = new Date().getMonth()

    wx.nextTick(() => {

      this.getHabitInfo(nowYear, nowMonth)

    })

  },

  // 获取子组件的数据

  getObj(e) {

    console.log("获取子组件的数据", e);

    this.setData({

      currentDate: e.detail.currentDate,

      currentMonth: e.detail.currentMonth,

      currentYear: e.detail.currentYear,

    })

    this.getHabitInfo(e.detail.currentYear, e.detail.currentMonth - 1)

  },

  // 获取当月的打卡数据

  getHabitInfo(year, month) {

    // 注意month范围 0-11,0代表1月

    const db = wx.cloud.database()

    db.collection('habitList').where({

      _id:this.data.id,

    }).get().then(res => {

      // console.log("从数据库获取数据[res]===", res);

      var dateTimeArr = res.data[0].dateTime

      var dateArr = []

      dateTimeArr.forEach((item) => {

        if (item.getFullYear() == year && item.getMonth() == month) {

          dateArr.push(item.getDate())

        }

      })

      console.log(year, month,this.data.currentDate);

      if (!this.data.currentDate ||(year==this.data.nowYear && month>this.data.nowMonth)||(year==this.data.nowYear && month==this.data.nowMonth &&this.data.currentDate>this.data.nowDate) ) {

        // 打卡按钮禁用的情况(1)页面初始化时,未点击任何日期(2)当前点击的日期在今天之后

        var flag = true

      } else {

        // 打卡按钮禁用的情况 (3)当前日期已打卡

        var flag = dateArr.indexOf(this.data.currentDate) == -1 ? false : true

      }

  

      this.setData({

        habitInfo: res.data[0],

        punchCardDateArr: dateArr,

        disabledFlag: flag,

        totalDays:dateTimeArr.length,

        monthDays:dateArr.length

      })

  

    }).catch(err => {

      console.log(err);

    })

  },

  // 点击打卡按钮-打卡

  punchCard() {

    console.log(this.data.currentYear, this.data.currentMonth - 1, this.data.currentDate);

    var currentTime = new Date(this.data.currentYear, this.data.currentMonth - 1, this.data.currentDate)

    const db = wx.cloud.database()

    db.collection('habitList').doc(this.data.id).update({

      data: {

       dateTime:db.command.push(currentTime)

      },

      success: res => {

        wx.showToast({

          title: '打卡成功',

        })

        this.getHabitInfo(this.data.currentYear, this.data.currentMonth - 1)

      },

      fail: err => {

        wx.showToast({

          icon: 'none',

          title: '新增记录失败'

        })

        console.error('[数据库] [新增记录] 失败:', err)

      }

    })

  }

})

【calendarCard.json】

1

2

3

4

5

6

{

  "usingComponents": {

    "top-title":"../../../components/topTitle/topTitle",

    "calendar":"../components/calendar/calendar"

  }

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/maidu_xbd/article/details/109651735
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计