前言在大多数客户端应用中,日期的选择和操作是一个常见的功能,使用日历组件来实现这一功能往往是一种高效的解决方案。对于日历组件的设计开发,在常见的开源项目中,通常有两种设计思路:横向切换显示,默认渲染单个月份,通过按键或左右滑动切换月份;垂直切换显示,默认呈现多个月份。月份,上下滑动切换月份;比如添加picker切换视图,添加自定义按钮,日期单选/多选,自定义文案,日期范围限制等功能,这些基本都是基于两个idea的功能扩展。在日常应用中,两种方式各有优缺点:横向切换,初始渲染节点较少,渲染性能较好;垂直切换,具有更直观的视觉体验和更好的交互操作;然而,鱼与熊掌不可兼得,交互体验与性能之间的权衡是必须始终直面的问题。随着移动设备的不断发展和移动浏览器的不断完善,用户设备的兼容性和运行效率得到了显着提高。因此本文主要介绍垂直切换实现的NutUICalendar日历组件。题目介绍今天的题目是NutUI日历组件的设计与实现。Calendar组件是NutUI的一个日历组件。用于为用户提供直观的日期选择方式,滑动切换月份,支持选择单个日期和日期范围,支持自定义日期内容等功能。今天,我们就来看看在组件开发过程中,如何一步步实现组件功能。组件设计思路对于日历组件来说,无论交互如何设计,日期时间数据的处理都是必不可少的。毕竟视图也是服务于数据信息的。本文采用的垂直切换显示方式,也意味着我们需要对节点的渲染性能做一些优化调整。因此,我们的实现思路主要有以下几点:日期数据处理,原始数据一次性初始化,可见区域节点元素分段渲染。应用虚拟列表的方法来降低节点元素的渲染成本。完善滚动事件和边界条件的处理功能,丰富Slots、Props、Events事件等,完善可扩展组件的实现原理。基本参数要求在处理日期数据时,我们需要首先指定我们需要的基本时间输入参数,例如:日历组件可选的时间范围,当前选择的时间。通过对传入参数的分析处理,得到我们需要的数据内容,并在后续的开发过程中,完成组件内容的渲染和事件处理。这里我画了一张图方便大家更好的理解:原始日期数据:就是我们根据日期范围计算出来的原始数据当前选择日期:显示当前月份在可见范围内,需要判断选择的日期是否在范围内daterange显示范围区间:根据当前选择的日期处理,是当前需要渲染的数据范围。容器大小信息:用于计算日期滚动和切换时的位移信息。日期数据处理日期数据的计算需要多个处理过程。首先,我们需要计算传入日期范围是否存在。如果不是,则默认使用最近一年的时间范围。然后计算存在多少个月。根据月数遍历生成日期数据。在计算单个月的日期时,每个月的第一天和一周的最后一天是不同的。我们需要根据不同的周数完成上个月和下个月的日期。这样既可以省去1号起始位置偏移量的计算,又可以为功能扩展做铺垫。//获取单个月份的日期和状态constgetDaysStatus=(currMonthDays:number,dateInfo:any)=>{let{year,month}=dateInfo;返回Array.from(Array(currMonthDays),(v,k)=>{return{day:k+1,type:"curr",year,month,};});//获取上个月最后一周的天数,填上当月的空白constgetPreDaysStatus=(preCurrMonthDays:numberweekNum:number,dateInfo:any,)=>{let{year,month}=日期信息;如果(周数>=7){周数-=7;}让months=Array.from(Array(preCurrMonthDays),(v,k)=>{return{day:k+1,type:"prev",year,month,};});返回months.slice(preCurrMonthDays-weekNum);};};处理后的数据如下:virtuallist当我们生成或加载数据量非常大时,会出现严重的性能问题,导致视图在一段时间内变得对操作无响应。小程序中视图渲染的问题更加明显。为了解决这个问题,虚拟列表是一个很好的解决方案:相对于全量渲染数据生成的视图,可以只渲染当前可见区域(visibleviewport)的视图。当用户滚动到可见区域时,将呈现不可见区域中的视图。比如Taro中的长列表渲染(虚拟列表):当然,以上只是一个简单的应用,日历组件的构建需要在此基础上进行优化。如下图所示,monthswrapper是需要显示月份的容器。这是因为在我们的视口中会有超过一个月的时间。同时,由于单个月份包含的节点较多,经过视口边界后渲染时可能会出现空白区域,因此我们可以保留月份的部分内容,在不可见区域更改渲染节点。如上图,scrollWrapper:是一个高度为总月高度的容器,主要用作viewport中的滚动容器;monthsWrapper:里面是当前渲染月份的容器;viewport:是当前的视口范围;当scrolling事件被触发时,scrollWrapper会向下或向上移动。到达边界后,monthsWrapper内部的月份信息发生变化,其整体高度也可能发生变化。通过修改monthsWrapper的transition,保证月份改变后,视口内的内容不变,更新视口外的数据。在应用虚拟列表的同时,结合目前主流的框架,将数据添加到框架的响应式数据中。该框架根据不同的数据使用diff算法或其他机制在一定程度上复用DOM节点,减少DOM节点的数量。元素的添加和删除操作。毕竟频繁增删DOM是一件比较耗性能的事情。
