码迷,mamicode.com
首页 > 其他好文 > 详细

模仿 Antd 写一个年份的时间选择器

时间:2020-01-17 21:30:38      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:row   ellipsis   white   connect   focus   before   方向   start   pac   

说明:

这篇文章复制不可用,代码真多,编辑不易。有需要联系我,谢谢。

功能介绍:

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

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

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

改进方向:

若有时间,我希望弹窗中的确定按钮可以由用户选择,是否需要使用。

当用户决定不使用确定按钮时,选择时间后弹窗自动收起,并且把选择的时间返出去。

大家若有什么好的建议,我也会采纳,主要是得有时间,??

吐槽一下:

这是多变态的产品,非得要一套“年份”的时间选择器

效果展示:

技术图片技术图片

js部份:

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

class YearPicker extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      open: false, // 是否展示弹窗
      year: "", // "2020"
      selectYear: "",
      yearListData: [], // 可选中的年份时间列表
      basePage: 0 // 基准页面
    }
  }

  componentDidMount() {
    const { value, open } = this.props;
    const { basePage } = this.state;
    const data = this.renderList(basePage)
    this.setState({
      selectYear: value,
      year: value,
      yearListData: data
    })
    if (open === undefined) {
      document.addEventListener("click", this.eventFn)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.value !== this.props.value) {
      this.setState({
        year: nextProps.value,
        basePage: 0
      })
    }
  }

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

  eventFn = (ev) => {
    const ary = [];
    ev.path.map(item => {
      ary.push(item.className)
    })
    if (!ary.includes("YearPicker")) {
      this.setState({ open: false })
    }
  }

  renderList = (basePage) => {
    // 太累了,这里省略部份代码
  }

  onclick = (ev) => {
    ev.stopPropagation();
    this.setState({ open: true })
  }

  yearClick = (ev, item) => {
    ev.stopPropagation();
    this.setState({ selectYear: item })
  }

  iconLeftClick = () => {
    console.log("左")
    const { basePage } = this.state;
    const data = this.renderList(basePage - 1);
    this.setState({
      basePage: basePage - 1,
      yearListData: data
    })
  }

  iconRightClick = () => {
    console.log("右")
    const { basePage } = this.state;
    const data = this.renderList(basePage + 1);
    this.setState({
      basePage: basePage + 1,
      yearListData: data
    })
  }

  okBut = (ev) => {
    ev.stopPropagation();
    const { selectYear } = this.state;
    this.setState({
      year: selectYear,
      open: false
    }, () => {
      this.props.onOk(selectYear)
    })
  }

  render() {
    const { year, open, selectYear, yearListData } = this.state;
    const { startValue, endValue } = this.props;
    let oneDisplay = "block", twoDisplay = "block";
    if (startValue && yearListData.includes(startValue)) {
      oneDisplay = "none";
    }
    if (endValue && yearListData.includes(endValue)) {
      twoDisplay = "none";
    }
    return (
      <div className="YearPicker" onClick={ev => { this.onclick(ev) }}>
        <div className="begin">
          <input className="zjl-text" defaultValue={year} />
          <i className="img" ></i>
        </div>
        <div className="yearChild" style={{ display: open ? "block" : "none" }}>
          <div className="hearer">
            <span className="left_icon" onClick={this.iconLeftClick} style={{ display: oneDisplay }}>{"<<"}</span>
            <span className="zjl-selectText">{selectYear}</span>
            <span className="right_icon" onClick={this.iconRightClick} style={{ display: twoDisplay }}>{">>"}</span>
          </div>
          <div className="con">
            <ul className="yearBefore">
              {
                yearListData.length > 0 &&
                yearListData.map((item, index) => {
                  return <li key={index}
                    onClick={(+startValue && +startValue <= +item) && (+endValue && +item <= +endValue) ? (ev) => { this.yearClick(ev, item) } : null}>
                    <span className={(+startValue && +startValue <= +item) && (+endValue && +item <= +endValue) ? selectYear === item ? "beforeli brackgroundYear" : "beforeli" : "beforeli warnnodata"}>
                      {item}
                    </span>
                  </li>
                })
              }
            </ul>
          </div>
          <div className="zjl-but">
            <span onClick={ev => { this.okBut(ev) }}>确 定</span>
          </div>
        </div>
      </div>
    )
  }
}

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

YearPicker.defaultProps = {
  value: moment().format("YYYY"),
  startValue: "1970",
  endValue: moment().format("YYYY"),
  open: undefined,
  onOk: () => { console.log(1) }
}

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

less部份:

.YearPicker{
  width: 100%;
  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-text{
      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: 32px;
      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);
      }
    }
    .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;
    }
  }
  .yearChild{
    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);
    .hearer{
      height: 40px;
      line-height: 40px;
      text-align: center;
      border-bottom: 1px solid #e8e8e8;
      user-select: none;
      white-space: nowrap;
      overflow: hidden;
      position: relative;
      span{
        display: inline-block;
      }
      .left_icon{
        position: absolute;
        z-index: 100;
        top: 0;
        left: 0;
        cursor: pointer;
        width: 30px;
        margin-left: 20px;
        &:hover{
          color: #40a9ff;
        }
      }
      .zjl-selectText{
        text-align: center;
      }
      .right_icon{
        position: absolute;
        z-index: 100;
        top: 0;
        right: 0;
        cursor: pointer;
        width: 30px;
        margin-right: 20px;
        &:hover{
          color: #40a9ff;
        }
      }
    }
    .con{
      width: 100%;
      .yearBefore{
        width: 100%;
        padding: 10px 20px;
        overflow: hidden;
        display: grid;
        grid-gap: 20px;
        grid-template-columns: repeat(3, 1fr);
        grid-auto-rows: 20px 20px 20px;
        grid-template-areas:
          "h h h"
          "h h h"
          "h h h"
          "h h h";
        li {
          text-align: center;
          font-size: 14px;
          .beforeli{
            display: inline-block;
            cursor: pointer;
            padding: 0 10px;
            height: 24px;
            line-height: 22px;
            &:hover{
              background: #e6f7ff;
            }
          }
          .brackgroundYear{
            background: #bae7ff;
            border-radius: 1px;
            &:hover{
              background: #bae7ff;
            }
          }
          .warnnodata{
            background-color: #f5f5f5;
            color: rgba(0, 0, 0, 0.25);
            cursor: not-allowed;
          }
        }
      }
    }
    .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;
        }
      }
    }
  }
}

模仿 Antd 写一个年份的时间选择器

标签:row   ellipsis   white   connect   focus   before   方向   start   pac   

原文地址:https://www.cnblogs.com/MrZhujl/p/12207277.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!