【毕业设计】基于微信小程序的备忘录记事助手

293 篇文章 9 订阅
266 篇文章 18 订阅

1 前言

Hi,大家好,学长今天向大家介绍 一个小程序项目

基于微信小程序的备忘录记事助手

大家可用于 毕业设计

2 简介

这次学长给大家介绍的是一个比较简单的小应用事项助手,其实跟事项也不沾多少边,只是作为辅助功能,只有数据的添加和删除,主要内容是日历这块内容。日历组件在web应用中应用非常广泛,插件也非常丰富,但是小程序不支持传统的插件写法,而是以数据驱动内容。

大部分的日历选择器都是差不多的,能显示当前的年份、月份和天数,可以选择某天、某月或者某年,我们可以打开操作系统中自带的日历观察一番。

日历的布局大同小异,本次案例的布局也是中规中矩,比较传统,头部显示当前年份月份,头部的左右个显示一个翻页按钮,跳转到上一月和下一月,下半部分显示当月的天数列表,由于每月的天数可能不一样,列表的格数是固定的,所以当月的天数显示使用高亮,其余的使用偏灰色彩。

实现效果如下

在这里插入图片描述

3 部分实现步骤与代码

3.1 对象方法属性

小程序的每一个页面都有一个相对应的js文件,里面必不可少的就是Page函数,Page函数接受的参数是一个对象,我们经常使用的写法就是:

Page({
    data: {
        userAvatar: './images/avatar.png',
        userName: 'Oopsguy'
    },
    onLoad: function() {
        //....
    },
    onReady: function() {
        //....
    }
});

现在换做ES6的写法,我们可以这样:

Page({
    data: {
        userAvatar: './images/avatar.png',
        userName: 'Oopsguy'
    },
    onLoad() {
        //....
    },
    onReady() {
        //....
    }
});

我们可以把以前的键值写法省略掉,而且function声明也不需要了。

class关键字用于声明类,constructor是构造函数,static修饰静态方法。不能理解?我们看一下以前的js的简单写法:

class Animal {
    constructor() {

    }

    eat() {

    }

    static doSomething(param) {
        //...
    }
}

module.exports = Animal;

var Animal = function() {

};

Animal.prototype.eat = function() {

};

Animal.doSomething = function(param) {

};

module.exports = Animal;

let animal = new Animal();
animal.eat();
//静态方法
Animal.doSomething('param');

3.2 箭头函数(Arrow Function)

箭头函数简化了函数的写法,但是还是跟普通的function有区别,主要是在作用域上。

比如我们需要请求网络:

wx.request({
  url: 'url', 
  header: {
      'Content-Type': 'application/json'
  },
  success: function(res) {
    console.log(res.data)
  }
});

用函数还是可以简化一定的代码量

wx.request({
  url: 'url', 
  header: {
      'Content-Type': 'application/json'
  },
  success: (res) => {
    console.log(res.data)
  }
});

注意到那个success指向的回调函数了么,function关键字没了,被醒目的=>符号取代了。看到这里大家是不是认为以后我们写function就用箭头函数代替呢?答案是不一定,而且要非常小心!

function和箭头函数虽然看似一样,只是写法简化了,其实是不一样的,function声明的函数和箭头函数的作用域不同,这是一个不小心就变坑的地方。

Page({
    data: {
        windowHeight: 0
    },
    onLoad() {
        let _this = this;
        wx.getSystemInfo({
            success: function(res) {
                _this.setData({windowHeight: res.windowHeight});
            }
        });
    }
});

一般我们获取设备的屏幕高度差不多是这样的步骤,在页面刚加载的onLoad方法中通过wx.getSystemInfoAPI来获取设备的屏幕高度,由于success指向的回调函数作用域跟onLoad不一样,所以我们无法像onLoad函数体中直接写this.setData来设置值。我们可以定义一个临时变量指向this,然后再回调函数中调用。

3.3 日历

建立工程的步骤就不讲了,直接进入主题,应用只有两个页面,一个首页,一个详情页,结构清晰,功能简单。

先来看看首页,日历的wxml结构;

结构分为上中下三部分,header为头部,用于展示翻页按钮和当前日期信息。在.week.row和.body.row元素中展示星期和天数列表,这里的布局采用了比较low的百分比分栏,总共有7栏,100/7哈哈,想高逼格的可以采用css的分栏布局和flex布局。

<view class="og-calendar">
    <view class="header">
        <view class="btn month-pre" bindtap="changeDateEvent" data-year="{{data.beforeYear}}" data-month="{{data.beforMonth}}"> 
            <image src="../../images/prepage.png"></image>
        </view>
        <view class="date-info">
            <picker mode="date" fields="month" value="{{pickerDateValue}}" bindchange="datePickerChangeEvent">
                <text>{{data.showYear}}{{data.showMonth > 9 ? data.showMonth : ('0' + data.showMonth)}}</text>
            </picker>
        </view>
        <view class="btn month-next" bindtap="changeDateEvent" data-year="{{data.afterYear}}" data-month="{{data.afterMonth}}">
            <image src="../../images/nextpage.png"></image>
        </view>
    </view>
    <view class="week row">
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
        <view class="col">
            <text></text>
        </view>
    </view>
    <view class="body row">  
        <block wx:for="{{data.dates}}" wx:key="_id">
            <view bindtap="dateClickEvent" data-year="{{item.year}}" data-month="{{item.month}}" data-date="{{item.date}}" class="col {{data.showMonth == item.month ? '' : 'old'}} {{data.currentDate == item.date && data.currentYear==item.year && data.currentMonth == item.month ? 'current' : ''}} {  {item.active ? 'active' : ''}}">
                <text>{{item.date}}</text>
            </view> 
        </block>
    </view>
</view>

.btn.month-pre和.btn.month-next翻页按钮,都绑定了changeDateEvent的tap事件,各自都用自己的data-year和data-mont属性,这两个属性是临时存值,当点击按钮翻页的时候,我们需要知道当前的年份和日期,以便可以更加方便地翻到上一页或者下一页。

changeDateEvent事件比较简单:

changeDateEvent(e) {
    const {year, month} = e.currentTarget.dataset;
    changeDate.call(this, new Date(year, parseInt(month) - 1, 1));
}

点击翻页按钮,根据回调进来的event对象来获取元素上的data-*属性,然后调用changeDate这个方法来更新日历数据,这个方法接收一个Date对象,代表要翻页后的日期。

暂且不关心changeDate具体干了些什么,看看.body.row里有一个循环,每一个元素都绑定了dateClickEvent事件,而且每一个元素都附带了自己所属的年份、月份和天数信息,这些信息是非常有用的,当点击了具体的某一天,可以通过获取元素上的data-*信息来知道我们具体选择的日期。除此之外,元素上的class属性包裹了一长串的判断表达式。这些语句最终的目的是为了给元素动态变更,.old代表当前的日期不是本月日期,因为每一版的日期除了当前月份的日期还可能包含上一月和下一月的部分日期,我们给予它灰色的样式显示,.current代表今天的日期,用实心填充颜色的背景样式修饰,.active即代表着当前选中的日期。

dateClickEvent事件其实也是调用了changeDate事件,本质上也是也是改变日期,额外的工作就是保存选中的日期到selected对象中。

dateClickEvent(e) {
    const {year, month, date} = e.currentTarget.dataset;
    const {data} = this.data;
    let selectDateText = '';

    data['selected']['year'] = year;
    data['selected']['month'] = month;
    data['selected']['date'] = date;

    this.setData({ data: data });

    changeDate.call(this, new Date(year, parseInt(month) - 1, date));
}

来看看重中之重的changeDate函数,这个函数的代码比较多,虽然堆砌大量在一个函数中是个不好的习惯,不过里面声明变量和赋值比较多,业务代码比较少:

/**
 * 变更日期数据
 * @param {Date} targetDate 当前日期对象
 */
function changeDate(targetDate) {
  let date = targetDate || new Date();
  let currentDateObj = new Date();

  let showMonth, //当天显示月份
    showYear, //当前显示年份
    showDay, //当前显示星期
    showDate, //当前显示第几天
    showMonthFirstDateDay, //当前显示月份第一天的星期
    showMonthLastDateDay, //当前显示月份最后一天的星期
    showMonthDateCount; //当前月份的总天数

  let data = [];

  showDate = date.getDate();
  showMonth = date.getMonth() + 1;
  showYear = date.getFullYear();
  showDay = date.getDay();

  showMonthDateCount = new Date(showYear, showMonth, 0).getDate();
  date.setDate(1);
  showMonthFirstDateDay = date.getDay(); //当前显示月份第一天的星期
  date.setDate(showMonthDateCount);
  showMonthLastDateDay = date.getDay(); //当前显示月份最后一天的星期  

  let beforeDayCount = 0,
    beforeYear, //上页月年份
    beforMonth, //上页月份
    afterYear, //下页年份
    afterMonth, //下页月份
    afterDayCount = 0, //上页显示天数
    beforeMonthDayCount = 0; //上页月份总天数

  //上一个月月份
  beforMonth = showMonth === 1 ? 12 : showMonth - 1;
  //上一个月年份
  beforeYear = showMonth === 1 ? showYear - 1 : showYear;
  //下个月月份
  afterMonth = showMonth === 12 ? 1 : showMonth + 1;
  //下个月年份
  afterYear = showMonth === 12 ? showYear + 1 : showYear;

  //获取上一页的显示天数
  if (showMonthFirstDateDay != 0)
    beforeDayCount = showMonthFirstDateDay - 1;
  else
    beforeDayCount = 6;

  //获取下页的显示天数
  if (showMonthLastDateDay != 0)
    afterDayCount = 7 - showMonthLastDateDay;
  else
    showMonthLastDateDay = 0;

  //如果天数不够6行,则补充完整
  let tDay = showMonthDateCount + beforeDayCount + afterDayCount;
  if (tDay <= 35)
    afterDayCount += (42 - tDay); //6行7列 = 42

  //虽然翻页了,但是保存用户选中的日期信息是非常有必要的  
  let selected = this.data.data['selected'] || { year: showYear, month: showMonth, date: showDate };
  let selectDateText = selected.year + '年' + formatNumber(selected.month) + '月' + formatNumber(selected.date) + '日';

  data = {
    currentDate: currentDateObj.getDate(), //当天日期第几天
    currentYear: currentDateObj.getFullYear(), //当天年份
    currentDay: currentDateObj.getDay(), //当天星期
    currentMonth: currentDateObj.getMonth() + 1, //当天月份
    showMonth: showMonth, //当前显示月份
    showDate: showDate, //当前显示月份的第几天 
    showYear: showYear, //当前显示月份的年份
    beforeYear: beforeYear, //当前页上一页的年份
    beforMonth: beforMonth, //当前页上一页的月份
    afterYear: afterYear, //当前页下一页的年份
    afterMonth: afterMonth, //当前页下一页的月份
    selected: selected,
    selectDateText: selectDateText
  };

  let dates = [];
  let _id = 0; //为wx:key指定

  //上一月的日期
  if (beforeDayCount > 0) {
    beforeMonthDayCount = new Date(beforeYear, beforMonth, 0).getDate();
    for (let fIdx = 0; fIdx < beforeDayCount; fIdx++) {
      dates.unshift({
        _id: _id,
        year: beforeYear,
        month: beforMonth,
        date: beforeMonthDayCount - fIdx
      });
      _id++;
    }
  }

  //当前月份的日期
  for (let cIdx = 1; cIdx <= showMonthDateCount; cIdx++) {
    dates.push({
      _id: _id,
      active: (selected['year'] == showYear && selected['month'] == showMonth && selected['date'] == cIdx), //选中状态判断
      year: showYear,
      month: showMonth,
      date: cIdx
    });
    _id++;
  }

  //下一月的日期
  if (afterDayCount > 0) {
    for (let lIdx = 1; lIdx <= afterDayCount; lIdx++) {
      dates.push({
        _id: _id,
        year: afterYear,
        month: afterMonth,
        date: lIdx
      });
      _id++;
    }
  }

  data.dates = dates;


  this.setData({ data: data, pickerDateValue: showYear + '-' + showMonth });
  loadItemListData.call(this);
}

4 最后

  • 1
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值