ui 参考 primeNG: http://primefaces.org/primeng…
ts 开发环境:https://github.com/lycHub/ts-…
简介
日历插件有很多,形态各异,但不管什么插件,只要掌握其基本实现原理,就能写出通用性很强的轮子。
本节日历 demo 和源码
已实现的功能:
- 不可选日期
- 默认选中日期
- 多面板
- 范围选择
- 自定义事件
基本思路
可以先把一个日历面板的静态布局写好,包括选中,非当月日期,禁止点击等样式:
写好静态部分后,可以先用假数据填充天数部分(就是所有的 td), 这些 td 我是用一个类似矩阵(6 行 7 列)的二维数组,用 for 循环生成的,
假的矩阵数组可以这样生成:
const dateArr = [];
for (let a = 0; a < 6; a++) {dateArr.push(Array(7).fill(a));
}
console.log(dateArr);
生成了一个假数据的面板后,可以思考怎么换成真数据,我的思路是:
取得每个月(比如截图的 2019.6)第一行第一列的日期,生成 6 * 7 个 td
在生成的时候判断每个 td 是否默认被选中,时候禁用,是否在当月(2019.6),是否当天,然后添加不同的 class 样式
也就是 DatePicker.ts 的这段:
这里面引入了日期库——date-fns,官方文档要翻墙,可以看这个翻译的 Docs
至于多面板,我是用 monthNum 控制的,默认为 1
dateArrs 组装成功后,就可以用 dom 操作渲染面板了,就是 DatePicker.ts 里的 initDatePicker 方法
切换月份
切换月份比较简单,只要处理好边界,在重新渲染一遍数据即可:
点击日期
首先禁用的不可点,然后是不是范围选择(options.range 是否为 true), 这个要分开写逻辑
不管什么选择,我这里先把所有 td 的 activedclass 去除了(这个去除时机并非最好)
如果不是范围选择,只需给点击的 td 加上 actived 的样式,赋值给_value,发射 onChange 事件
如果是范围选择:
要区分点击次数,处理两次点击目标的时间先后顺序
配置项和自定义事件
经常写插件的也许不用说也知道,这两个特性是插件必备的。
配置项和自定义事件的设计都是参照黄大仙 Bscroll 的,
配置项有默认的一套,用户传入后进行合并,也就是我源码中 Options.ts 的逻辑
自定义事件的逻辑在 EventEmitter.ts 中,我只实现了点击 td 的 change 事件,用户可以在配置项中监听,也可以调用实例上的 on 方法
源码我已经写了足够详细的注释,可以 clone 下拉直接运行,我的实现思路可能不是最好的,欢迎网友们晒出自己的 demo 和建议咯.