唯心主义蠢货的[UI组件_5]时间选择器

实现一个简易版的时间选择器

实现效果:

在这里插入图片描述

逻辑分析与代码实现

数据

  1. date(year,month,day) 构造函数,month从 0 - 11分别对应一月到十二月,day设置为0时,是上一个月的最后一天,如果设置为当前月最大天的下一天,则为下一个月的第一天。
  2. 对于选择日期,一个月最少28天,再考虑到月初和月末可能和邻近日期不在同一周的情况,因此我们需要一个6*7的二维数组去储存,日期的更改实际上是对于这个数组的更新。
  3. 每个数组元素储存一个对象,此对象包含 label:当前日期,date:对应年月日,isMonth:是否为当前月的元素,渲染时直接每个单元格对应一个数组元素,显示label,根据isMonth判断分属不同的类,判断默认日期激活active
function datePicker() {
    let date = new Date();

    // 选择的这一天
    this.currentDay = {
        year: date.getFullYear(),
        month: date.getMonth(),
        day: date.getDate(),
    };
    // 表头
    this.weeks = [ '日', '一', '二', '三', '四', '五', '六' ];

    this.dateArray = [];

    this.changeDateArray();
}


datePicker.prototype.changeDate = function (type , value){
    this.dateArray.splice(0, this.dateArray.length);
    if(type == 'year'){
        this.currentDay.year = value ;
    }
    else if(type == 'month'){
        this.currentDay.month = value %12;
        this.currentDay.year += parseInt(value/12);
        console.log(value)
    }
    else if(type == 'day'){
        this.currentDay.day = value;
    }
    this.changeDateArray();
}


datePicker.prototype.changeDateArray = function f() {

    let firstDay = new Date(this.currentDay.year, this.currentDay.month, 1);
    let offsetDay = -firstDay.getDay() + 1;
    for (let i = 0; i < 6; i++) {
        let arrayRow = [];
        for (let j = 0; j < 7; j++) {
            const day = i * 7 + j + offsetDay;
            const dayObject = new Date(this.currentDay.year, this.currentDay.month, day);
            let mState = false;
            let dState = false;
            if (dayObject.getMonth()  == this.currentDay.month) {
                mState = true;
            }

            if (dayObject.getDate() == this.currentDay.day) {
                dState = true;
            }
            arrayRow.push({
                theDate: getFormat(dayObject),
                label: dayObject.getDate(),
                monthState: mState,
                dayState: dState,
            });
        }
        this.dateArray.push(arrayRow);
    }
};

function getFormat( date ) {
    let year = date.getFullYear();
    let month = date.getMonth();
    let day = date.getDate();

    return year + '-' + (month + 1) + '-' + day;
}

选择面板部分

  1. 点击input当focus后,显示选择面板,默认显示当前月份,然后在顶栏可以进行年份和月份的选择
  2. 选择年份,则弹出今年所在的10年段,选择月份,则显示十二月份
  3. 同时需要储存一个对象保存选择的年月日,根据这个进行date的构造

控制面板显示

  1. 当显示默认面板之后,再次点击input,则仍处于focus状态,不做处理
  2. 当点击非input位置,即input.onblur时,则进入判断,如果是在面板区域则恢复focus,如果不是在面板区域则设置visible为false
  Input.onblur = function(){
      if (如果鼠标点击位置在面板内) {
          Input.focus();
          return;
      }
      else{
          document.onmousedown = null;
          _this.datePanelVisible = false;
      };
  }
  1. 判断是否在面板区域,则需要读取鼠标位置,但由于鼠标位置是相对于body的,所以我们也需要获得面板相对于body的位置,el.offsetLeft是相对于定位元素的left偏移量,el.offsetParent是定位元素,因此可以通过向上寻找定位元素直到body并累加偏移量的方式,获得当前元素与body的偏移量。
let left = 0;
let top = 0;
while( el.tagname !==  'body'){
	left += el.offsetLeft;
	top += el.offsetTop;
	el = el.offsetParent;
	}

难点

  • 面板内部的交互逻辑,div结构和数据
  • 控制面板显示部分的交互,涉及到input的focus和blur,以及如何获取元素相对于body的位置
  • 如何维护更新控制数据的二维数组
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值