快来看看我是如何更改Antd中DatePicker周选择器默认设置的?

2,795 阅读8分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战

前言

实际项目我们经常会使用别人UI框架,对于前端来说使用已有的成熟的UI框架会提高开发效率,但同时也会带来不满足需求从而促使我们去改别人东西的可能性,一单出现这样的需求就会使得前端开发很被动,毕竟那是别人的思想编码的结果,而我们现在要去更改别人的劳动成果,先不说难度,主要是时间,我们要先去理解别人为啥这样做之后才能去准确的做出更改范围和影响,所以这就很难受,毕竟改别人的东西是最耗时也是最痛苦的。

实际开发中有遇到这样的要求,你得先求证此要求的必要性,如果只是为了改而改那就是不合理的,那就商量商量尽量不去对已有的UI框架做更改,而是改变需求来满足UI组件;如果需求使得UI组件不满足,那就只有祈祷别人提供了API,不然那就只有动动别人的代码。我们尽可能还是要避免最差可能的发生,尽量换个方式或者绕个弯去解决需求。

我这次要聊的幸好别人提供了对应的API可以做修改,不然我真就要绕个弯去解决了。

需求背景

在我们项目中,我们使用的UI框架是选择蚂蚁的Antd框架,主要还是由于我们现在的技术栈属于React的缘故。我们需求就是要走我们使用的Antd框架中的DatePicker组件的周选择器做以下改动:

1.每周从周日开始
2.每年的第一周改为当前年的1月1日所在的周
3.更改样式

为什么需要做上面的需求,也就是原因是啥?最核心的需求其实是因为我们公司有着自己的一套周定义规则,就是每年1号所在的周就是当年的第1周,所以就产生了如上需求。我们先来看看Antd提供的周选择器默认展示是啥样:

微信截图_20220123101216.png

可以看到AntdDatePicker组件默认的是:每周从周一开始;每年的最后一周是31号所在的周,若包含来年的1号,那就归为去年的最后一周,否则就是来年的第一周;显然是不匹配我们需求的,那就不得不做更改了。先看看最终效果:

微信截图_20220123102538.png

这下通过两张图的对比,应该清楚我们需求是怎样的了,以及我们要聊什么问题了吧。OK,实现方法往下看。

开发

说实话,其实一拿到这个需求我就很笃定的给产品说Antd本身好像不支持我们做这样的修改,因为我详细地看了DatePicker组件的API,没有提供一个直接的API来更改周默认的显示。于是我就建议产品换一个方式来解决,即用后端人员提供的查询自己定义周的接口来间接的实现上述需求,产品也同意了。具体想法如下:

那就是底层还是使用DatePicker组件,只是在用户选择时间了之后通过选择的时间去查询这个时间所在的周;然后先通过display: none把周信息数字给隐藏起来,接着用样式定位盖一个Div盒子在DatePicker组件上,用于显示查询回来的周信息;当用户需要更改时,那就添加点击事件穿透打开DatePicker的下拉选择时间容器进行选择。

这真是黔驴技穷的尴尬解决方式,经过思想的斗争觉得Antd这么大一个厂不至于这么low不支持这样的更改吧,所以我们就去查rc-DatePicker插件和看DatePicker所使用的moment.js之后,终于在moment.js中找到了比上述方法更简洁完美的方法,这下可以说避免了更多代码的编写和改别人组件的举动,真是‘你好我好大家好’的完美局面。

下面提供两种方式,小伙伴们根据自己的情况去自行选择,两种方式都可实现上述需求,开始我的表演^_^

原理

查询momonet.js文档,可以在右侧菜单中找到自定义选项,然后在文档下方找到week选项,文档就有如下说明:

Locale#week.dow:代表星期中第一天的整数,0是星期日、1是星期一、...、6是星期六。

Locale#week.doy:须为整数。doy与dow一起用于判断年份中的第一周。 
doy的计算方式为7 + dow - janX,其中janX是一月的第一天(必须属于年份中的第一周)。

看懂了么?意思就是week的默认受这两个值的影响,dow是控制周几的位置显示。若设置为0就是星期日开始排列;若为1则是星期一开始排列,以此类推。而doy则是计算年份第一周的逻辑的,若要想1月1日所在周为第一周且星期一排在第一位,则doy等于7 + 1 - 1 = 7。注意moment.js版本,具体请看示例代码:

// 从 2.12.0 开始 
moment.updateLocale('en', { 
    week : { 
        dow : Int, 
        doy : Int 
    } 
});

// 从 2.8.1 至 2.11.2 
moment.locale('en', { 
    week : { 
        dow : Int, 
        doy : Int 
    } 
});

// 废弃于 2.8.1 
moment.lang('en', { 
    week : { 
        dow : Int, 
        doy : Int 
    } 
});

全局配置

其实能做更改,是需要项目安装了moment.js插件并在项目中使用了。需在全局文件index.tsx中作如下代码修改:

import 'moment/locale/zh-cn';
import moment from 'moment';

moment.locale('zh-cn', {
    week: {
        dow: 1,
        doy: 7
    }
});

这就是全局进行配置主要代码,这里一改项目中所有的用到DatePicker周选择器的地方都会变成统一设置,这就是全局配置唯一不好的,像我们项目遵循我们自己已有的周定义规则,所以适用于全局配置。至于小伙伴们没有那就使用下面的局部页面配置也能达到效果。

局部配置

局部配置就是为了不想像全局配置那样一旦配置凡是引用了DatePicker周选择器组件的页面都是一样的配置,毕竟每个页面有每个页面需求场景,所以促使我们得了解局部配置的使用方法。局部配置就是在不同的页面配置不一样的属性达到不同的需求,就算全局有了配置,一旦页面有配置先使用页面配置的,没有就使用全局配置的。局部配置的方法如下所示:

1)引入moment.js插件:
import moment from "moment";

2)增加代码:
useEffect(() => {
    moment.updateLocale('zh-cn', {
        week: {
            dow: 1,
            doy: 7
        }
    });
}, []);

上面所展示的就是局部配置的方法代码,就是使用moment.jsupdateLocale方法去修改默认值,计算方式与原理所讲一致。所以一旦找到对应的API改起来还是挺方便的,所以这告诉我们在使用别人的UI框架时,要多去查看别人提供的API属性和了解其演变的过程和使用的插件信息,这样方便我们准确的定位信息而不至于走其他弯路。

样式修改

我们UI需要我们将DatePicker组件的样式做一些调整,我们就给其定义一个类名,防止污染全局样式。注意:下面代码是DatePicker周范围选择器的样式更改代码,DatePicker周选择器的样式更改大同小异,这里不贴代码:

<RangePicker
    className="bit-week-range"
    dropdownClassName="bit-week-dropdown"
    picker="week"
/>

style: 
.bit-week-range {
    width: 224px;
    background-color: transparent;
    border-color: rgba(255, 255, 255, 0.24);
    .ant-picker-input > input {
        color: #fff;
    }

    .ant-picker-input > input:hover {
        border-color: transparent;
        border-right-width: 1px !important;
    }

    .ant-picker-input > input:focus, .ant-picker-input > input-focused {
        border-color: transparent;
        box-shadow: inherit;
    }

    .ant-picker-active-bar {
        background: #d9d9d9;
    }

    .ant-picker-range-separator {
        .ant-picker-separator {
            color: #fff
        }
    }

    .ant-picker-suffix {
        color: #fff;
    }

    .ant-picker-clear {
        color: #fff;
        background-color: #000;
    }
}

效果:

微信截图_20220123134009.png

微信截图_20220123134415.png

微信截图_20220123134719.png

往期精彩文章

后语

伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注在走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。