纯手工打造的日期选择器 xy-date-picker 原理与使用

简介: 纯手工打造的日期选择器 xy-date-picker 原理与使用

最近花了差不多快两周的空闲时间打造了一个日期选择组件,先看看效果

image.png

可以说是一个经常要用到,很少人会主动去实现的一个组件,毕竟实现起来还是要一定的时间的,所以平时工作之余就可以试着打造一些基础组件库,既可以锻炼自己的基本功,又可以为公司为社区做贡献~


先看一下用法吧,推荐查看文档,可以实时交互


安装使用


通常有以下几种安装方式


  • npm
npm i xy-ui


  • cdn
<script type="module" src="https://unpkg.com/xy-ui/components/xy-pagination.js"></script>
<!--或者-->
<script type="module">
    import 'https://unpkg.com/xy-ui/components/xy-pagination.js'
</script>


  • github


直接从github拷贝源码。


使用

<xy-date-picker></xy-date-picker>


一个标签的事,开箱即用,可能是使用起来最方便的日期选择器了。


实现原理


这里简单介绍一下日期的生成原理


要实现一个月的展示,一般分为三个部分,分别为前一个月,当前月,下一个月


image.png

为此,我们需要知道


1.前一个月的最后一天

2.当前月的天数及当前月第一天是周几(便于摆放位置)


假如前一个月最后一天是31号,并且当月的第一天是周二及总天数30,那么这个月的排列就确定了


30 31 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 1 2 3


首先是获取一个月的最后一天,通常每个月的天数是固定的,只有二月不固定,有一种做法是把二月单独列出来,通过计算闰年的方式来判断是29还是28。


其实还有一种方式可能方便,我们可以直接利用日期的容错机制,比如

new Date(2019,2,1) //2019年3月1日
new Date(2019,2,0) //2019年3月1日的前一天,也就是2019年2月的最后一天


然后获取当天的日期,也就是当月天数

new Date(2019,2,0).getDate() //28


然后是获取一个月的第一天是星期几,这个比较容易

new Date(2019,2,1).getDay() //5,周五


然后我们可以通过这些信息组合出一个月份信息

function getDays(year,month){
    const lastdays = new Date(year,month-1,0).getDate();
    const days = new Date(year,month,0).getDate();
    const week = new Date(year,month-1,1).getDay();
    const prev = Array.from({length:week},(el,i)=>(month==0?year-1:year)+'-'+(month==0?12:month-1)+'-'+(lastdays+i-week+1));
    const current = Array.from({length:days},(el,i)=>year+'-'+month+'-'+(i+1));
    const next = Array.from({length:42 - days - week},(el,i)=>(month==12?year+1:year)+'-'+(month==12?1:month+1)+'-'+(i+1));
    return [...prev,...current,...next];
}


这里简单做了一个在控制台输出日历


image.png


源码如下,小伙伴可以试试

function renderCalendar(d){ 
        const date = new Date(d||new Date); 
        const year = date.getFullYear(); 
        const month = date.getMonth(); 
        const day = date.getDate(); 
        const lastdays = new Date(year,month,0).getDate(); 
        const days = new Date(year,month+1,0).getDate(); 
        const week = new Date(year,month,1).getDay(); 
        const prev = Array.from({length:week},(el,i)=>([month==0?year-1:year,month==0?12:month,lastdays+i-week+1])); 
        const current = Array.from({length:days},(el,i)=>[year,month+1,i+1]); 
        const next = Array.from({length:42 - days - week},(el,i)=>([month==11?year+1:year,month==11?1:month+2,i+1])); 
        const final = [...prev,...current,...next]; 
        const now = Array.from({length:6},(el,i)=>final.slice(i * 7, i * 7 + 7)); 
        const s = `———————————————————————————————————— 
             ${year+' - '+(month+1+'').padStart(2,0)}
%c———————————————————————————————————— 
| Su | Mo | Tu | We | Th | Fr | Sa | 
———————————————————————————————————— 
%c${now.map(el=>el.map(m=>(m[2]==1?'%c':'')+'| '+((m[2]+'').padStart(2,' ')+' ')).join('')+'|\n————————————————————————————————————\n').join('')}
        ` 
        console.clear(); 
        console.log(s,"font-weight:bold;color:blue","color:#999","color:#000","color:#999") 
    }


以上就是日期生成原理了,进一步可以实现日期切换,单选,范围选择等功能。


属性


xy-date-picker定义以下几种属性,结合使用适用性更广。


默认值defaultvalue


可以给日期选择器指定一个初始日期defaultvalue,取值为合法的时间戳字符串DataString,默认为当前日期。


支持形如以下的字符串,可参考Date.parse()

"2019-2-28"
"2019-02-28"
"2019/2/28"
"2019,2,28"
"2019 2 28"
"Feb 28 2019"
//...其他日期格式
//以上均表示2019年2月28日。
<xy-date-picker defaultvalue="2019-2-28"></xy-date-picker>


image.png

类型type


支持设置日期选择类型,可选择date(默认)、monthyear,分别实现日期选择器、月选择器、年选择器。

<xy-date-picker></xy-date-picker>
<xy-date-picker type="month"></xy-date-picker>
<xy-date-picker type="year"></xy-date-picker>

image.png

image.png

value、日期date


设置或返回日期选择器的value属性值。值为当前类型下的日期,格式形如2019-10-10


返回日期的标准格式date,可以将值转换成任意格式的日期。

//value
"2019-08-31"
//date
"Sat Aug 31 2019 14:54:05 GMT+0800 (中国标准时间)"


可以通过JavaScript设置或获取。

date.value; //获取
date.date; //获取
date.value = '2019-10-10';
//原生属性操作
date.getAttribute('value');
date.getAttribute('date');
date.setAttribute('value','2019-10-10');


最小值min、最大值max


设置日期选择范围,超出范围之外的不可选中,格式同defaultvalue

<xy-date-picker min="2019-8-20" max="2019-12-21"></xy-date-picker>
<xy-date-picker type="month" min="2019-5" max="2019-12"></xy-date-picker>
<xy-date-picker type="year" min="2018" max="2050"></xy-date-picker>


image.png

image.png

禁用disabled


通过disabled可以禁用,禁用后无法打开日期选择器。

<xy-date-picker disabled></xy-date-picker>


image.png

方向


通过dir可以设置日期选择器方向,默认为bottomleft,可以取值toprightbottomlefttoplefttoprightrighttoprightbottombottomleftbottomrightlefttopleftbottom。当你的日期选择器位于屏幕边缘时可以调整该属性。

<xy-date-picker dir="righttop"></xy-date-picker>


image.png

范围选择range


添加range属性可以实现日期范围选择。

<xy-date-picker range></xy-date-picker>


image.png

可以指定一个默认范围defaultvalue,格式形如2019-10-10~2019-12-31,用~链接。默认为当前日期。

<xy-date-picker range defaultvalue="2019-10-10~2019-12-31"></xy-date-picker>


范围选择模式下的valuedate均为数组

//value
["2019-05-15", "2019-12-26"]
//date
["Wed May 15 2019 08:00:00 GMT+0800 (中国标准时间)", "Thu Dec 26 2019 08:00:00 GMT+0800 (中国标准时间)"]


事件event


当选好日期后,按确定按钮可以触发change回调。

<xy-date-picker onchange="console.log(event)"></xy-date-picker>

image.png

event:{
    detail:{
        value,
        date
    }
}


其他触发方式

date.onchange = function(ev){
    console.log(this.value);
    console.log(this.date);
    console.log(ev.target.value);
    console.log(ev.detail.value);
    console.log(ev.detail.date);
}
date.addEventListener('change',function(ev){
    console.log(this.value);
    console.log(this.date);
    console.log(ev.target.value);
    console.log(ev.detail.value);
    console.log(ev.detail.date);
})


其他


xy-date-picker内部基于xy-popoverxy-date-pane实现。

<xy-popover >
    <xy-button class="date-btn"></xy-button>
    <xy-popcon>
        <xy-date-pane id="color-pane"></xy-date-pane>
        <div class="pop-footer">
            <xy-button id="btn-cancel">取消</xy-button>
            <xy-button type="primary" id="btn-submit">确认</xy-button>
        </div>
    </xy-popcon>
</xy-popover>


其中,xy-date-pane为日期选择面板,可独立使用,如果你只是想要一个日历,可以使用这个组件。

<xy-date-pane></xy-date-pane>


image.png

事件和属性与xy-date-picker一致。


小节


总体来说,xy-date-picker使用起来还是很容易的,无需写大量脚本,就像使用一个input,大部分情况只需知道一个onchange事件就可以了。


其实xy-ui的组件设计都是靠近原生的,没有那些自创的事件,比如这里的onchange有些日期组件库就喜欢搞成datechange什么的,虽然语义很好,但是不够原生,不够统一,用户完全无感,不看文档完全不知道下手,反倒是原生更具有代表性,规范性,可以说拿到这个组件,往页面上一放,根本无需看api文档即可上手大部分功能。


目前xy-ui已经完成了大部分常见组件,后续有其他会陆续补充,希望有需要的小伙伴可以马上用起来,也希望可前往github给颗star,谢谢~


相关文章
使用云起实验室安装Stable Diffusion报错问题的解决
因为huggingface目前国内已无法访问,按照原有的手册安装时就会报错,本文给出解决办法,以顺利完成安装和使用
3928 0
uniapp页面之间通信、传参、传值方法(父→传→子,子→传→父);获取被打开页面的数据→传→当前页面;当前页面的数据→传→被打开页面
uniapp页面之间通信、传参、传值方法(父→传→子,子→传→父);获取被打开页面的数据→传→当前页面;当前页面的数据→传→被打开页面
|
存储 缓存 开发者
Mooncake 最新进展:SGLang 和 LMCache 基于 Mooncake 实现高效 PD 分离框架
近期,Mooncake 项目与 SGLang、vLLM 等主流大模型推理框架实现合作和适配,这些开源大模型推理框架可以通过使用 Mooncake 发布的 whl 包,支持 pip安装,docker 镜像部署等,实现了 PD 分离框架,极大提升了模型推理效率。
|
6月前
|
安全 JavaScript Linux
【OpenClaw🦞AI龙虾保姆级教程】无代码阿里云/Win11/Mac/Linux部署+百炼API配置及Skills筛选指南
“模型很强,但干活总差一口气”“装了一堆技能,反而更慢更乱”“想接内部工具,却不知道从哪下手”——这是2026年多数OpenClaw(昵称“小龙虾”)用户的共性困惑。作为开源AI代理框架,OpenClaw的核心价值不在于基础对话能力,而在于通过“技能(Skills)”扩展功能边界,但海量技能的筛选、安全风险的规避、系统的长期维护,成为新手落地的三大拦路虎。
884 1
|
安全 关系型数据库 MySQL
Mysql 8.0 安装和使用遇到的各种问题(持续更新)
MySQL 8.0 安装到 服务器时,遇到的一些问题;安装、远程访问、密码编码格式不对、大小写区分、密码重置、修改密码 等操作
|
移动开发 前端开发 JavaScript
UniApp H5项目大揭秘:高效生成与扫描二维码的终极策略,让你的应用脱颖而出!
【8月更文挑战第3天】UniApp让开发者能以Vue.js构建跨平台应用。在H5项目中,通过第三方库如qrcodejs2可轻松生成二维码,代码简洁易集成;或用Canvas API获得更高灵活性。扫描方面,H5+ API适合App环境,而纯H5项目则需前端库加后端服务配合。不同方法各有优势,应按需选择以优化体验。
1581 0
|
人工智能 小程序 Java
接入QAnything的AI问答知识库,可私有化部署的企业级WIKI知识库
zyplayer-doc是一款适合企业和个人使用的WIKI知识库管理工具,提供在线化的知识库管理功能,专为私有化部署而设计,最大程度上保证企业或个人的数据安全,可以完全以内网的方式来部署使用它。 您也可以将其作为企业产品的说明文档来使用,支持一键将整个空间的内容开放到互联网,提供有不同风格的开放文档页样式可供选择,以及适配了在手机端、小程序中文档的展示,省去为产品的说明文档而定制开发系统的成本。
2241 0
|
Rust 资源调度 前端开发
【一起学Rust | 框架篇 | Tauri2.0框架】使用Barcode Scanner实现扫码功能(安卓)
【一起学Rust | 框架篇 | Tauri2.0框架】使用Barcode Scanner实现扫码功能(安卓)
1420 0

热门文章

最新文章