专栏首页IMWeb前端团队如何使用 React 构建自定义日期选择器(3)

如何使用 React 构建自定义日期选择器(3)

本文作者:IMWeb howenhuo 原文出处:IMWeb社区 未经同意,禁止转载

接着上一篇:如何使用 React 构建自定义日期选择器(2)

Datepicker 组件

构建 Datepicker 组件

要开始构建 Datepicker 组件,请将以下代码片段添加到 src/components/Datepicker/index.js 文件。

import React from "react";
import PropTypes from "prop-types";
import Calendar from "../Calendar";
import * as Styled from "./styles";
import { isDate, getDateISO } from "../../helpers/calendar";

class Datepicker extends React.Component {

  state = { date: null, calendarOpen: false }

  toggleCalendar = () => this.setState({ calendarOpen: !this.state.calendarOpen })

  handleChange = evt => evt.preventDefault()

  handleDateChange = date => {
    const { onDateChanged } = this.props;
    const { date: currentDate } = this.state;
    const newDate = date ? getDateISO(date) : null;

    currentDate !== newDate &&
      this.setState({ date: newDate, calendarOpen: false }, () => {
        typeof onDateChanged === "function" && onDateChanged(this.state.date);
      });
  }

  componentDidMount() {
    const { value: date } = this.props;
    const newDate = date && new Date(date);

    isDate(newDate) && this.setState({ date: getDateISO(newDate) });
  }

  componentDidUpdate(prevProps) {
    const { value: date } = this.props;
    const { value: prevDate } = prevProps;
    const dateISO = getDateISO(new Date(date));
    const prevDateISO = getDateISO(new Date(prevDate));

    dateISO !== prevDateISO && this.setState({ date: dateISO });
  }

}

Datepicker.propTypes = {
  label: PropTypes.string,
  value: PropTypes.string,
  onDateChanged: PropTypes.func
}

export default Datepicker;

在这里,组件 state 初始化为两个属性:

  • date:一个 ISO string,表示日期选择器的当前日期。格式是 “YYYY-MM-DD”
  • calendarOpen :一个 boolean 标记,表示日期选择器的日历是否可见。

当组件 mount 时,Date 对象从传递给组件 props 的 value 解析,并更新 state,如componentDidMount() 方法所示。

handleDateChange() 方法以 Date 对象作为参数,并更新 state 下的 date。如果 Datepicker 组件的 props 传递了 onDateChanged 回调函数,则将使用更新的 ISO 日期字符串调用该函数。

渲染 datepicker

此时,值得一提的是,Bootstrap Dropdown 组件将用于模拟自定义日期选择器的下拉效果。这就是为什么 Reactstrap 包被添加为此项目的依赖项的原因。

正如您很快会注意到,在日期选择器中渲染的样式化组件是 Reactstrap 下拉组件的样式扩展。

更新 Datepicker 组件以包含 render() 方法,如下面的代码片段所示。

class Datepicker extends React.Component {

  // ... other methods here

  render() {
    const { label } = this.props;
    const { date, calendarOpen } = this.state;

    return (
      <Styled.DatePickerContainer>

        <Styled.DatePickerFormGroup>

          <Styled.DatePickerLabel>{label || 'Enter Date'}</Styled.DatePickerLabel>

          <Styled.DatePickerInput
            type="text"
            value={date ? date.split("-").join(" / ") : ""}
            onChange={this.handleChange}
            readOnly="readonly"
            placeholder="YYYY / MM / DD"
          />

        </Styled.DatePickerFormGroup>

        <Styled.DatePickerDropdown isOpen={calendarOpen} toggle={this.toggleCalendar}>

          <Styled.DatePickerDropdownToggle color="transparent" />

          <Styled.DatePickerDropdownMenu>
            { calendarOpen && (
              <Calendar date={date && new Date(date)} onDateChanged={this.handleDateChange} />
            )}
          </Styled.DatePickerDropdownMenu>

        </Styled.DatePickerDropdown>

      </Styled.DatePickerContainer>
    );
  }

}

Styled.DatePickerFormGroup 组件是一个 Bootstrap 的 .form-group,它包装日期选择器标签和输入字段。需要注意的是,输入字段的类型是 “text”,并且标记为 readonly,这样就无法直接编辑它。还要注意,输入元素上的 change 事件的默认行为已经被阻止。

Styled.DatePickerDropdown 组件及其后代,是 ReactstrapDropdown 组件的样式扩展。您可以在 这里 了解更多关于 Reactstrap 下拉列表的信息。

最后,Calendar 组件在下拉菜单中渲染,传递 state 中的 dateonDateChanged 回调函数的handleDateChange() 方法。

Datepicker 组件最终渲染的 DOM 应该如下所示(带有一些样式):

设置日期选择器的样式

将以下代码片段添加到 src/components/Datepicker/styles.js,以创建日期选择器所需的样式组件。

import styled from 'styled-components';
import { FormGroup, Label, Input, Dropdown, DropdownToggle, DropdownMenu } from 'reactstrap';

export const DatePickerContainer = styled.div`
  position: relative;
`;

export const DatePickerFormGroup = styled(FormGroup)`
  display: flex;
  justify-content: space-between;
  position: relative;
  width: 100%;
  border: 2px solid #06c;
  border-radius: 5px;
  overflow: hidden;
`;

export const DatePickerLabel = styled(Label)`
  margin: 0;
  padding: 0 2rem;
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: #06c;
  border-right: 2px solid #06c;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 102, 204, 0.05);
`;

export const DatePickerInput = styled(Input)`
  padding: 1rem 2rem;
  font-weight: 500;
  font-size: 1rem;
  color: #333;
  box-shadow: none;
  border: none;
  text-align: center;
  letter-spacing: 1px;
  background: transparent !important;
  display: flex;
  align-items: center;
  ::placeholder {
    color: #999;
    font-size: 0.9rem;
  }
`;

export const DatePickerDropdown = styled(Dropdown)`
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
`;

export const DatePickerDropdownToggle = styled(DropdownToggle)`
  position: relative;
  width: 100%;
  height: 100%;
  background: transparent;
  opacity: 0;
  filter: alpha(opacity=0);
`;

export const DatePickerDropdownMenu = styled(DropdownMenu)`
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  border: none;
  padding: 0;
  margin: 0;
  transform: none !important;
`;

应用程序组件

最后,更新 src/App.js 文件,看起来像下面的代码片段。

import React, { Component } from "react";
import Datepicker from "./components/Datepicker";

class App extends Component {
  render() {
    return (
      <div className="w-25 py-5 my-5 mx-auto">
        <Datepicker label="Birthday" value="2000-08-15" />
      </div>
    );
  }
}

export default App;

如果您按照本文和代码片段进行操作,则应该在 React 应用程序中渲染出一个可用的自定义日期选择器。

结论

在本教程中(123),您已经能够逐步了解如何构建一个定制的 React 日期选择器组件,该组件可以作为原生 HTML5 日期选择器输入元素的替代。

虽然本教程中创建的自定义日期选择器能按预期工作,但它并不能完全满足日期选择器元素的所有要求。可以进一步改进,例如:

  • 通过 props 实现 maxmin 日期
  • 将输入类型从 “text” 切换到 “date”
  • 更好的可访问性改进

你可以在 react-datepicker-demo 的 GitHub 上获得这个自定义日期选择器的更多改进版本的完整源代码。 您还可以在 Code Sandbox 上查看演示。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • jQuery选择器总结

    本文作者:IMWeb 一大碗油茶 原文出处:IMWeb社区 未经同意,禁止转载 不得不说,jq是写代码是替代js的一种超级棒的选择。对于刚入门的小白都...

    IMWeb前端团队
  • jQuery选择器总结

    不得不说,jq是写代码是替代js的一种超级棒的选择。对于刚入门的小白都知道,一般学前端,都要用js写tab切换,大图滚动之类的效果,同样的效果,js大概20-4...

    IMWeb前端团队
  • 如何成为一名卓越的前端工程师

    译注:本文翻译自谷歌工程师 Philip Walton 的一篇博客。看过之后非常有感触,很多观点都是自己长期非常坚持和认同的,所以翻译出来分享给更多的前端同学!

    IMWeb前端团队
  • 30分钟开发一款抓取网站图片资源的浏览器插件

    由于业务需求, 笔者要为公司开发几款实用的浏览器插件,所以大致花了一天的时间,看完了谷歌浏览器插件开发文档,在这里特地总结一下经验, 并通过一个实际案例来复盘插...

    徐小夕
  • 【干货】从零实现 react-redux

    在 React 诞生之初,Facebook 宣传这是一个用于前端开发的界面库,仅仅是一个 View 层。前面我们也介绍过 React 的组件通信,在大型应用中,...

    winty
  • 【Node.js】IntelliJ IDEA 集成插件的两种方式

    step1. 点击file->setting->Plugins,点击Browse repositiories,然后搜索nodejs,点击安装。

    魏晓蕾
  • Instrumentation框架介绍-Android自动化测试系列(三)

    子勰
  • hdu---(4310)Hero(贪心算法)

    Hero Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java...

    Gxjun
  • jetbrains 离线安装插件

    jetbrains 的 vim 插件很好用,绝大部分 vim 的功能都具备了,由于升级了 jetbrains 系列 ide, 不支持旧版本的 ideaVim 插...

    章鱼喵
  • 打造前端 Deepin Linux 工作环境——安装配置 atom 编辑器

    打造前端 Deepin Linux 工作环境——安装配置 atom 编辑器 好,我个人推荐大家使用 atom 编辑器,第一是免费,第二是好看,第三是好用。 安装...

    FungLeo

扫码关注云+社区

领取腾讯云代金券