模仿 Antd 写一个季度的时间选择器 V2.0

说明:

版本:V2.0

此文章代码复制不可用,有需要可以留言,或者联系我。

功能介绍:

1.可以设置 可选择的时间范围,范围超出部分置灰不可选择。

2.点击空白处默认收起弹窗,也可以在外部通过 open 属性控制。

3.按确定按钮后过 onOk 属性返回 一个函数,第一个参数为选择的时间。

4.*新增:用户可以选择是否使用确定按钮。

5.*新增: disabled (禁用状态)、className (设置选择器)、defaultValue(时间为空时的默认显示) 。

6.宽高自动获取父级,最小高度22px,最下宽度90px。

改进方向:

此版本基本满足开发时的各种需要,及突发情况。目前暂无改进计划。

观众老爷们若有什么好的建议,我也会采纳,主要是得有时间。😊

效果展示:

更多版本:

  ts 版 (网友 Ever-Lose 改进提供的)

js(部分代码):

import React from "react";
import "./QuarterlyPicker.less"
import moment from "moment";
import { connect } from "react-redux";
import PropTypes from "prop-types";

const quarterData = ["第一季度", "第二季度", "第三季度", "第四季度"];

class QuarterlyPicker extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      stateOpen: false, // 是否展示弹窗
      year: "", // "2020"
      selectTime: `${moment().format("YYYY")}-${moment().quarter()}`, // 选中的时间, "2020-1", "-1" 代表第一季度
      selectionTime: "", // 点确定后需要返回的时间
      oneDisplay: "block",
      twoDisplay: "block"
    }
  }

  componentDidMount() {
    const { value, open } = this.props;
    let { year, selectTime } = this.state;
    year = value ? value.split("-")[0] : selectTime.split("-")[0]
    this.setState({
      selectTime: value ? value : selectTime,
      selectionTime: value ? value : "",
      year
    })
    this.idBlock(year)
    if (open === undefined) {
      document.addEventListener("click", this.eventFn, true)
    }
  }

  componentWillUnmount() {
    document.removeEventListener("click", this.eventFn, true)
  }

  eventFn = (ev) => {
    // ...
  }

  onclick = (ev) => {
    // ...
  }

  ulliclick = (index) => {
    // ...
  }

  iconLeftClick = () => {
    // ...
  }

  iconRightClick = () => {
    // ...
  }

  idBlock = (year) => {
    // ...
  }

  okBut = (ev) => {
    // ...
  }

  textChange = () => {
    // ...
  }

  quarterDataBefore = () => {
    // ...
  }

  render() {
    const { oneDisplay, twoDisplay, selectTime, year, selectionTime, stateOpen } = this.state;
    const { className, defaultValue, disabled, showOk, open } = this.props;
    let openOnOff = false;
    if (typeof (this.props.open) === "boolean") {
      openOnOff = open;
    } else {
      openOnOff = stateOpen;
    }
    return (
      <div className={`QuarterlyPicker ${className}`} id="QuarterlyPicker" onClick={disabled ? console.log("禁用") : ev => { this.onclick(ev) }}>
        <div className="begin">
          <input className={selectionTime ? "zjl-input" : "zjl-input default_input"}
            value={selectionTime ? selectionTime : defaultValue}
            disabled={disabled}
            onChange={() => { this.textChange() }}
          />
          <i className="img" ></i>
        </div>
        <div className="child" style={{ display: openOnOff ? "block" : "none" }}>
          <header className="zjl-timehear">
            <span>{selectTime}</span>
          </header>
          <div className="con">
            <ul className="content-one">
              <li className="lefticon" onClick={this.iconLeftClick} style={{ display: oneDisplay }}>{"<<"}</li>
              <li className="righticon" onClick={this.iconRightClick} style={{ display: twoDisplay }}>{">>"}</li>
              <li>{year}</li>
            </ul>
          </div>
          <div className="TimerXhlleft">
            <ul className="quaterleft">
              {this.quarterDataBefore()}
            </ul>
          </div>
          {
            showOk ?
              <div className="zjl-but">
                <span onClick={this.okBut}>确 定</span>
              </div> : null
          }
        </div>
      </div>
    )
  }
}

QuarterlyPicker.propTypes = {
  value: PropTypes.string,
  startValue: PropTypes.string,
  endValue: PropTypes.string,
  open: PropTypes.bool,
  onOk: PropTypes.func,
  disabled: PropTypes.bool
}

QuarterlyPicker.defaultProps = {
  showOk: false, // 是否使用确定按钮,默认不使用
  disabled: false, // 组件是否禁用,默认组件可以使用
  defaultValue: "请选择时间", // 默认日期 or 没有日期时的提示语
  value: "",
  startValue: "1970-1",
  endValue: `${moment().format("YYYY")}-${moment().quarter()}`,
  open: undefined,
  onOk: () => { console.log(1) },
  className: ""
}

export default connect(state => state, {})(QuarterlyPicker)

less部份:

.QuarterlyPicker{
  width: 100%;
  height: 100%;
  min-height: 22px;
  min-width: 90px;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  color: rgba(0, 0, 0, 0.65);
  font-size: 14px;
  font-variant: tabular-nums;
  line-height: 1.5;
  list-style: none;
  font-feature-settings: 'tnum';
  position: relative;
  display: inline-block;
  outline: none;
  cursor: text;
  transition: opacity 0.3s;
  .begin{
    position: relative;
    height: 100%;
    .zjl-input{
      text-overflow: ellipsis;
      touch-action: manipulation;
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      font-variant: tabular-nums;
      list-style: none;
      font-feature-settings: 'tnum';
      position: relative;
      display: inline-block;
      width: 100%;
      height: 100%;
      padding: 4px 11px;
      color: rgba(0, 0, 0, 0.65);
      font-size: 14px;
      line-height: 1.5;
      background-color: #fff;
      background-image: none;
      border: 1px solid #d9d9d9;
      border-radius: 4px;
      transition: all 0.3s;
      &:hover{
        border-color: #40a9ff;
        border-right-width: 1px !important;
      }
      &:focus {
        border-color: #40a9ff;
        border-right-width: 1px !important;
        outline: 0;
        box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
      }
    }
    .zjl-input[disabled] {
      color: rgba(0, 0, 0, 0.25);
      background-color: #f5f5f5;
      cursor: not-allowed;
      opacity: 1;
    }
    .default_input{
      color: rgba(0, 0, 0, 0.25);
    }
    .img{
      display: inline-block;
      position: absolute;
      top: 50%;
      right: 12px;
      height: 14px;
      width: 14px;
      margin-top: -7px;
      background: url("../../assets/imgs/日历1.png") no-repeat center;
      background-size: 100% 100%;
      color: rgba(0, 0, 0, 0.25);
      font-size: 14px;
      line-height: 1;
      z-index: 1;
      transition: all 0.3s;
      user-select: none;
    }
  }
  .child{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    color: rgba(0, 0, 0, 0.65);
    font-variant: tabular-nums;
    line-height: 1.5;
    list-style: none;
    font-feature-settings: 'tnum';
    position: absolute;
    z-index: 1050;
    width: 280px;
    font-size: 14px;
    line-height: 1.5;
    text-align: left;
    list-style: none;
    background-color: #fff;
    background-clip: padding-box;
    border: 1px solid #fff;
    border-radius: 4px;
    outline: none;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    .zjl-but {
      position: relative;
      height: auto;
      text-align: right;
      padding: 0 12px;
      line-height: 38px;
      border-top: 1px solid #e8e8e8;
      span{
        position: relative;
        display: inline-block;
        font-weight: 400;
        white-space: nowrap;
        text-align: center;
        background-image: none;
        border: 1px solid transparent;
        box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
        cursor: pointer;
        transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
        user-select: none;
        touch-action: manipulation;
        height: 32px;
        padding: 0 15px;
        color: #fff;
        background-color: #1890ff;
        border-color: #1890ff;
        text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
        -webkit-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
        box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
        height: 24px;
        padding: 0 7px;
        font-size: 14px;
        border-radius: 4px;
        line-height: 22px;
        &:hover{
          color: #fff;
          background-color: #40a9ff;
          border-color: #40a9ff;
        }
      }
    }
    .zjl-timehear{
      height: 34px;
      padding: 6px 10px;
      border-bottom: 1px solid #e8e8e8;
      span{
        display: inline-block;
        width: 100%;
        margin: 0;
        cursor: default;
      }
    }
    .TimerXhlleft{
      width: 100%;
      padding: 20px;
      .quaterleft{
        display: flex;
        width: 100%;
        flex-direction: row;
        flex-wrap: wrap;
        justify-content: space-between;
        .quaterleftli{
          width: 43%;
          margin-right: 0 !important;
          text-align: center;
          line-height: 50px;
          height: 50px;
          color: #333;
          .normalcolor{
            display: inline-block;
            line-height: 30px;
            height: 30px;
            padding: 0 20px;
            cursor: pointer;
            &:hover{
              background: #e6f7ff;
              cursor: pointer;
            }
            &.nonormaocolor{
              background: #bae7ff;
              border-radius: 1px;
              // color: #fff;
            }
            &.warnnodata{
              background: #F5f5f5;
              color: rgba(0, 0, 0, 0.25);
              cursor: not-allowed;
            }
          }
        }
      }
    }
    .con{
      height: 40px;
      line-height: 40px;
      text-align: center;
      border-bottom: 1px solid #e8e8e8;
      user-select: none;
      .content-one{
        white-space: nowrap;
        overflow: hidden;
        position: relative;
        .lefticon{
          position: absolute;
          z-index: 100;
          top: 0;
          left: 0;
          font-size: 18px;
          cursor: pointer;
          width: 30px;
          margin-left: 20px;
          &:hover{
            color: #40a9ff;
          }
        }
        .righticon{
          position: absolute;
          z-index: 100;
          top: 0;
          right: 0;
          font-size: 18px;
          cursor: pointer;
          width: 30px;
          margin-right: 20px;
          &:hover{
            color: #40a9ff;
          }
        }
        li {
          display: inline-block;
          text-align: center;
          cursor: default;
        }
      }
    }
  }
}

 

posted @ 2020-01-19 16:43  真的想不出来  阅读(2059)  评论(12编辑  收藏  举报