微信小程序:日历模块页面

2023-11-17


在这里插入图片描述

完整项目下载:下载链接

1 前言

在制作背单词打卡小程序中,用户需要方便地查看历史学习信息。为了使页面美观并保持交互简洁,采用日历作为日期选择器是极为必要的。本指南将教你如何开发一个功能完备的微信小程序日历模块页面,以提升用户体验。

2 功能需求

在开发背单词打卡小程序的日历模块页面时,我们需要满足以下功能需求:

(1)日期选择功能
用户可以通过点击日历中的具体日期来进行选择。这将使用户能够快速切换到所需的日期,方便查看该日期下的学习记录。

(2)学习记录标记
在已有学习记录的日期下,我们将通过标记小点的方式提醒用户该日期有学习记录。这种直观的视觉反馈将帮助用户快速辨识出打卡情况。

3 界面展示

在这里插入图片描述
在这里插入图片描述

4 部分代码展示

(1)代码目录
在这里插入图片描述

(2)util.js

const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}

const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

module.exports = {
  formatTime: formatTime
}

(3)index.js

//index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    dateString: "",
    spot: ['2022/8/6', '2022/8/9', '2022/8/20', '2022/9/12']
  },
  dateChange(e) {
    console.log("选中日期变了,现在日期是", e.detail.dateString)
    this.setData({
      dateString: e.detail.dateString
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

(4) calendar.js

// components/calendar/calendar.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    spot: {
      type: Array,
      value: []
    },
    defaultTime: {
      type: String,
      value: ''
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    dateList: [], //日历主体渲染数组
    selectDay: {}, //选中时间
  },

  /**
   * 组件的方法列表
   */
  methods: {
    /**
     * 时间戳转化为年 月 日 时 分 秒
     * time: 需要被格式化的时间,可以被new Date()解析即可
     * format:格式化之后返回的格式,年月日时分秒分别为Y, M, D, h, m, s,这个参数不填的话则显示多久前
     */
    formatTime(time, format) {
      function formatNumber(n) {
        n = n.toString()
        return n[1] ? n : '0' + n
      }

      function getDate(time, format) {
        const formateArr = ['Y', 'M', 'D', 'h', 'm', 's']
        const returnArr = []
        const date = new Date(time)
        returnArr.push(date.getFullYear())
        returnArr.push(formatNumber(date.getMonth() + 1))
        returnArr.push(formatNumber(date.getDate()))
        returnArr.push(formatNumber(date.getHours()))
        returnArr.push(formatNumber(date.getMinutes()))
        returnArr.push(formatNumber(date.getSeconds()))
        for (const i in returnArr) {
          format = format.replace(formateArr[i], returnArr[i])
        }
        return format
      }

      function getDateDiff(time) {
        let r = ''
        const ft = new Date(time)
        const nt = new Date()
        const nd = new Date(nt)
        nd.setHours(23)
        nd.setMinutes(59)
        nd.setSeconds(59)
        nd.setMilliseconds(999)
        const d = parseInt((nd - ft) / 86400000)
        switch (true) {
          case d === 0:
            const t = parseInt(nt / 1000) - parseInt(ft / 1000)
            switch (true) {
              case t < 60:
                r = '刚刚'
                break
              case t < 3600:
                r = parseInt(t / 60) + '分钟前'
                break
              default:
                r = parseInt(t / 3600) + '小时前'
            }
            break
          case d === 1:
            r = '昨天'
            break
          case d === 2:
            r = '前天'
            break
          case d > 2 && d < 30:
            r = d + '天前'
            break
          default:
            r = getDate(time, 'Y-M-D')
        }
        return r
      }
      if (!format) {
        return getDateDiff(time)
      } else {
        return getDate(time, format)
      }
    },
    //picker设置月份
    editMonth(e) {
      const arr = e.detail.value.split("-")
      const year = parseInt(arr[0])
      const month = parseInt(arr[1])
      this.setMonth(year, month)
    },
    //上月切换按钮点击
    lastMonth() {
      const lastMonth = new Date(this.data.selectDay.year, this.data.selectDay.month - 2)
      const year = lastMonth.getFullYear()
      const month = lastMonth.getMonth() + 1
      this.setMonth(year, month)
    },
    //下月切换按钮点击
    nextMonth() {
      const nextMonth = new Date(this.data.selectDay.year, this.data.selectDay.month)
      const year = nextMonth.getFullYear()
      const month = nextMonth.getMonth() + 1
      this.setMonth(year, month)
    },
    //设置月份
    setMonth(setYear, setMonth, setDay) {
      if (this.data.selectDay.year !== setYear || this.data.selectDay.month !== setMonth) {
        const day = Math.min(new Date(setYear, setMonth, 0).getDate(), this.data.selectDay.day)
        const time = new Date(setYear, setMonth - 1, setDay ? setDay : day)
        const data = {
          selectDay: {
            year: setYear,
            month: setMonth,
            day: setDay ? setDay : day,
            dateString: this.formatTime(time, "Y-M-D")
          }
        }
        if (!setDay) {
          data.open = true
        }
        this.setData(data)
        this.dateInit(setYear, setMonth)
        this.setSpot()
        this.triggerEvent("change", this.data.selectDay)
      }
    },
    //展开收起
    openChange() {
      this.setData({
        open: !this.data.open
      })
      this.triggerEvent("aaa", { a: 0 })
      this.dateInit()
      this.setSpot()
    },
    //设置日历底下是否展示小圆点
    setSpot() {
      const timeArr = this.data.spot.map(item => {
        return this.formatTime(item, "Y-M-D")
      })
      this.data.dateList.forEach(item => {
        if (timeArr.indexOf(item.dateString) !== -1) {
          item.spot = true
        } else {
          item.spot = false
        }
      })
      this.setData({
        dateList: this.data.dateList
      })
    },
    //日历主体的渲染方法
    dateInit(setYear = this.data.selectDay.year, setMonth = this.data.selectDay.month) {
      let dateList = []; //需要遍历的日历数组数据
      let now = new Date(setYear, setMonth - 1)//当前月份的1号
      let startWeek = now.getDay(); //目标月1号对应的星期
      let dayNum = new Date(setYear, setMonth, 0).getDate() //当前月有多少天
      let forNum = Math.ceil((startWeek + dayNum) / 7) * 7 //当前月跨越的周数
      if (this.data.open) {
        //展开状态,需要渲染完整的月份
        for (let i = 0; i < forNum; i++) {
          const now2 = new Date(now)
          now2.setDate(i - startWeek + 1)
          let obj = {};
          obj = {
            day: now2.getDate(),
            month: now2.getMonth() + 1,
            year: now2.getFullYear(),
            dateString: this.formatTime(now2, "Y-M-D")
          };
          dateList[i] = obj;
        }
      } else {
        //非展开状态,只需要渲染当前周
        for (let i = 0; i < 7; i++) {
          const now2 = new Date(now)
          //当前周的7天
          now2.setDate(Math.ceil((this.data.selectDay.day + startWeek) / 7) * 7 - 6 - startWeek + i)
          let obj = {};
          obj = {
            day: now2.getDate(),
            month: now2.getMonth() + 1,
            year: now2.getFullYear(),
            dateString: this.formatTime(now2, "Y-M-D")
          };
          dateList[i] = obj;
        }
      }
      this.setData({
        dateList: dateList
      })
    },
    //一天被点击时
    selectChange(e) {
      const year = e.currentTarget.dataset.year
      const month = e.currentTarget.dataset.month
      const day = e.currentTarget.dataset.day
      const dateString = e.currentTarget.dataset.dateString
      const selectDay = {
        year: year,
        month: month,
        day: day,
        dateString: dateString
      }
      if (this.data.selectDay.year !== year || this.data.selectDay.month !== month) {
        this.setMonth(year, month, day)
      } else if (this.data.selectDay.day !== day) {
        this.setData({
          selectDay: selectDay
        })
        this.triggerEvent("change", this.data.selectDay)
      }
    }
  },
  lifetimes: {
    attached() {
      let now = this.data.defaultTime ? new Date(this.data.defaultTime) : new Date()
      let selectDay = {
        year: now.getFullYear(),
        month: now.getMonth() + 1,
        day: now.getDate(),
        dateString: this.formatTime(now, "Y-M-D")
      }
      this.setMonth(selectDay.year, selectDay.month, selectDay.day)
    }
  },
  observers: {
    spot: function (spot) {
      this.setSpot()
    }
  }
})

5 结语

通过本篇指南,我们深入探讨了开发微信小程序日历模块页面的过程。从功能需求到设计与布局,再到数据处理与存储,每个步骤都是为了实现一个方便用户查看历史学习记录的实用工具。

通过日历作为日期选择器,用户可以轻松地找到特定日期,而学习记录的标记则为用户提供了直观的提示。这些功能的实现不仅有助于提升用户体验,还为用户提供了更高效的背单词打卡体验。

当然,本文的指南只是一个开发的起点。在实际开发中,你可以根据自己的需求和技术水平,进行更多的优化和定制。我们鼓励你不断学习和创新,以提升自己在微信小程序开发领域的能力。

希望本篇指南能够帮助你成功开发一个出色的微信小程序日历模块页面,为用户提供更好的学习记录管理体验。祝你的开发之路愉快,期待你的小程序能够为用户带来便捷和价值。

注意:本文的指南提供了开发方向,具体实现可能因情况而异。开发者应根据实际需求和技术能力做出相应调整。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信小程序:日历模块页面 的相关文章

随机推荐

  • 初识C语言(二)

    目录 五 字符串 六 转义字符 七 注释 7 1注释的类型 7 1 1单行注释 7 1 2多行注释 7 2注释的使用方法 7 2 1解释代码功能注释 7 2 2提供代码示例注释 7 2 3禁用或屏蔽代码 八 选择语句 8 1if语句 8 1
  • 利用python3自动在36kr里查找自己感兴趣的内容

    最近常常在36kr网站的快讯及资讯 最新里查看自己感兴趣内容的及时信息 由于快讯及资讯 最新里信息更新得比较及时快速 自己也很难一直盯着看 故想着要是写个脚本让其自动在后天挂着每隔5分钟查询一次 有的话就写入txt档中并在控制台打印出来 这
  • 小孩学创客编程好还是学机器人好

    小孩学创客编程好还是学机器人好 小孩的学习一直都是很多家长们非常关心和重视的一件事情 很多的家长在培养孩子的学习的时候 可以说是十分的用心的 会给孩子选择一些能够有利于孩子成长的课程 就拿现在很多的家长想要孩子去学习机器人编程的课程来说 有
  • 域环境的搭建的详细教程-220109

    参考链接 https mp weixin qq com s src 11 timestamp 1641696209 ver 3547 signature zTIDZEcpq zjwuEuZpbaaAxFfkkVxcLHeX4AuKT78bJ
  • 第九届蓝桥杯 2018年省赛真题 (Java 大学C组 )

    蓝桥杯 2018年省赛真题 Java 大学C组 第一题 哪天返回 第二题 猴子分香蕉 第三题 字母阵列 第四题 第几个幸运数 第五题 书号验证 第六题 打印大X 第七题 缩位求和 第八题 等腰三角形 第九题 小朋友崇拜圈 第十题 耐摔指数
  • RHCE——DNS的正反向解析

    一 实验要求 DNS配置正反向解析 二 实验过程 1 安装软件包 root localhost ll yum install bind y 2 备份bind软件的的配置文件 root localhost yum repos d cp a e
  • CMAKE学习——编译多个文件 & 多个目录

    大型工程会有很多文件 包括类的实现和定义 各种不同的模块交叉在一起 我们怎么用cmake方便的编译呢 例如有这么一个工程 我们现在想要编译的话 如果只选择了main cpp 则会提示 未定义的引用 因为我们头文件和实现分离 但我们只包含了头
  • 【云原生之Docker实战】使用Docker部署jenkins持续集成工具

    云原生之Docker实战 使用Docker部署jenkins持续集成工具 一 jenkins介绍 1 jenkins简介 2 jenkins功能 3 jenkins基本工作图 二 检查本地系统版本 三 检查本地docker状态 1 检查do
  • IDEA运行报错:类文件具有错误的版本 55.0, 应为 52.0 请删除该文件或确保该文件位于正确的类路径子目录中。

    IDEA运行报错 类文件具有错误的版本 55 0 应为 52 0 请删除该文件或确保该文件位于正确的类路径子目录中 如果搜索资料 会看到minor major版本 但其实不叫这个名字 Sun公司会在大的版本升级时增加major数字 小更新或
  • 【python】自动化测试框架--nose

    目录 一 准备 二 nose介绍 三 看个简单的例子了解下 三 nose常用命令简单介绍 1 查看所有nose相关命令 2 执行并捕获输出 3 提供XUnit XML 格式的测试结果 并存储在nosetests xml文件中 主要为jenk
  • 程序员的自我修养--链接、装载与库

    中国科学技术大学软件学院 周艾亭 原创作品版权所有转载请注明出处 第一次接触 程序员的自我修养 的时候 的确怀有一种疑惑的态度的 因为潜意识告诉我 在计算机这一行 更强调的是实践动手 而XXX修养的显然不属于动手操作类 至少不是太适合我的需
  • 数据同步方案

    mysql 数据同步到elastic中 本文中不提及实现 仅提供方案 增量数据同步 方案一 通过logstash 官方提供的工具 快速实现数据同步 值得注意的是选择logstash时需要和elastic的版本做对应 由于elastic 版本
  • 多线程经典案例(生产者--消费者)

    多线程开发中有一个经典的操作案例 就是 生产者 消费者 案例 生产者不的生产产品 消费者不断地取走产品 此案例涉及线程同步 线程休眠 线程等待 线程唤起等操作以及之间是如何搭配使用的方法 示例讲解 本示例模拟中生产者由 厨师 担任 消费者由
  • 如何利用 Selenium 对已打开的浏览器进行爬虫

    大家好 在对某些网站进行爬虫时 如果该网站做了限制 必须完成登录才能展示数据 而且只能通过短信验证码才能登录 这时候 我们可以通过一个已经开启的浏览器完成登录 然后利用程序继续操作这个浏览器 即可以完成数据的爬取了 具体操作步骤如下 1 1
  • QT循环队列实时处理数据(二)

    上一篇多线程介绍的是 QT多线程处理机制 这篇 将对接收数据 实时处理进行分析 QT通过socket通信 从接收缓冲区中读取数据 交给线程进行处理 那么问题来了 如果线程还没有处理完数据 则线程就没有办法继续从缓冲区中取数 那么当数据量过大
  • vue父子组件之间的传值(子传父,父传子)

    vue父子组件之间的传值 子传父 父传子 前提首先需要了解vue中组件之间的父子关系 主组件mainPage vue
  • 个性化定制界面和极简版原装界面,哪一个你用起来更加顺手呢

    个性化定制界面是根据用户的需求和喜好进行定制的 具有很高的灵活性和可定制性 用户可以自由选择界面的颜色 布局 字体等 以及添加或删除特定功能 这种界面能够根据用户的个人喜好和习惯进行定制 使得用户在使用过程中更加舒适和顺手 以下是一些可能的
  • 【数据结构】&&【C++】平衡搜索二叉树的模拟实现(AVL树)

    数据结构 C 平衡搜索二叉树的模拟实现 AVL树 一 AVL树的性质 二 AVL树的模拟实现 AVL树结点的定义 AVL树的插入 平衡因子的更新 左单旋 右单旋 双旋 左右旋 右左旋 AVL树的删除 检查是否是AVL树 三 完整代码 一 A
  • Tp5 left join 带条件 数据不返回

    背景 下面两种方式都是在查询吸毒人员的基本信息 pa account 表示该吸毒人员的评估小组 一般情况下 录入吸毒人员基础信息都会录入其关联的评估小组 但是部分也不录入 理论上 无论评估小组有没有录入 left join 都要返回左表ad
  • 微信小程序:日历模块页面

    文章目录 1 前言 2 功能需求 3 界面展示 4 部分代码展示 5 结语 完整项目下载 下载链接 1 前言 在制作背单词打卡小程序中 用户需要方便地查看历史学习信息 为了使页面美观并保持交互简洁 采用日历作为日期选择器是极为必要的 本指南