zoukankan      html  css  js  c++  java
  • react 实战:写一个年份选择器

    上代码。

    组件的Js文件。

    import React, { Component } from "react";
    import Style from './myYearSelect.less'
    
    function getOffsetTop(el){
      return el.offsetParent
       ? el.offsetTop + getOffsetTop(el.offsetParent)
       : el.offsetTop
    }
    function getOffsetLeft(el){
      return el.offsetParent
       ? el.offsetLeft + getOffsetLeft(el.offsetParent)
       : el.offsetLeft
    }
    
    class YearPicker extends Component {
      constructor(props) {
          super(props);
          this.state = {
            isShow: false,
            selectedyear:"",
            boxPos:{},
            years: []
          };
      }
    
      componentWillMount() {
        let { defaultValue } = this.props;
        if (defaultValue) {
          this.setState({ selectedyear: defaultValue });
        }
      }
      componentDidMount() {
        let _this = this;
        document.addEventListener(
            "click",
            _this.clickFunc,
            false
        );
      }
      componentWillUnmount(){
        let _this = this
        document.removeEventListener(
          "click",
          _this.clickFunc,
          false
        );
      }
      clickFunc = e => { 
        const { isShow } = this.state;
        let clsName = e.target.className;
        // console.log(e.target.dataset)
        if (!e.target.dataset || !e.target.dataset.tag || e.target.dataset.tag !== "year") {
          this.onBlurFunc()
        }
      }
      onFocusFunc = e => {
        const { selectedyear } = this.state;
        const operand = 12;
        const d = document.documentElement || document.body || null
        let top, left
    
        this.initData(operand, selectedyear);
        
        if (d) {
          top = d.scrollTop
          left = d.scrollLeft
        }
        this.setState({
          isShow: true,
          boxPos:{
            x: getOffsetTop(e.currentTarget) - (top ? top : 0),
            y: getOffsetLeft(e.currentTarget) - (left ? left : 0),
          }
        })
      }
      onBlurFunc = e => {
        this.setState({
          isShow: false
        })
      }
      // 向前的年份
      prev = () => {
        const { years } = this.state;
        if (years[0] <= 1970) {
            return;
        }
        this.getNewYearRangestartAndEnd("prev");
      };
      // 向后的年份
      next = () => {
        this.getNewYearRangestartAndEnd("next");
      };
      getNewYearRangestartAndEnd = type => {
        const { selectedyear, years } = this.state;
        let operand = Number(this.props.operand);
        operand = operand ? operand : 12;
        let start = Number(years[0]);
        let end = Number(years[years.length - 1]);
        let newstart;
        let newend;
        if (type == "prev") {
            newstart = parseInt(start - operand);
            newend = parseInt(end - operand);
            this.getYearsArr(newstart, newend);
        }
        if (type == "next") {
            newstart = parseInt(start + operand);
            newend = parseInt(end + operand);
            this.getYearsArr(newstart, newend);
        }
      }
      initData = (operand, defaultValue) => {
        operand = operand ? operand : 12;
    
        let year = defaultValue - 1970;
        let curr = year % operand;
        let start = defaultValue - curr;
        let end = parseInt(defaultValue) + parseInt(operand) - 1 - curr;
        this.getYearsArr(start, end);
      };
      getYearsArr = (start, end) => {
        let arr = [];
        for (let i = start; i <= end; i++) {
            arr.push(Number(i));
        }
        this.setState({
            years: arr
        });
      };
      // 选中某一年
      selects = e => {
        let val = Number(e.target.value);
        this.setState({ selectedyear: val });
        if (this.props.callback) {
            this.props.callback(val);
        }
      };
    
    
    render() {
        const { width } = this.props
        const { isShow, boxPos, selectedyear, years } = this.state;
        const w = width ? width : 200
    
        return (
            <div className={Style.main} data-tag="year">
              <input className={Style.mainInput}
                data-tag="year"
                value={selectedyear}
                readOnly
                onFocus={this.onFocusFunc}
              />
              { isShow && boxPos.x ? <div data-tag="year" tabIndex="0" className={Style.box} 
                style={{ top:boxPos.x, left: boxPos.y, w }}>
                  <List
                  data={years}
                  value={selectedyear} 
                  prev={this.prev}
                  next={this.next}
                  cback={this.selects}
                  />
                </div> : '' }
            </div>
        );
    }
    }
    
    const List = props => {
      const { data, value, prev, next, cback } = props;
      return (
          <div className={Style.list} tabIndex="-1" data-tag="year">
              <div className={Style.header} data-tag="year">
                <a
                    type="double-left"
                    role="button"
                    className={Style.prevBtn}
                    onClick={prev}
                    data-tag="year"
                ></a>
                <span data-tag="year">{value}</span>
                <a
                    type="double-left"
                    role="button"
                    className={Style.nextBtn}
                    onClick={next}
                    data-tag="year"
                ></a>
              </div>
              <div className={Style.body} data-tag="year">
                  <ul className={Style.yearUl} data-tag="year">
                    {data.map((item, index) => (
                        <li
                            key={index}
                            title={item}
                            data-tag="year"
                            className={
                              item == value
                                  ? Style.calendarYearSelected
                                  : ""
                            }
                        >
                            <button onClick={cback} value={item}>
                                {item}
                            </button>
                        </li>
                    ))}
                  </ul>
              </div>
          </div>
      );
    };
    
    export default YearPicker;

    组件的 Less 文件。

    .main{
      width: 100%;
    }
    .mainInput{
      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;
    }
    .box{
      // width: 100%;
      height: 260px;
      max-width: 400px;
      // max-height: 400px;
      background-color: #fff;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
      position: fixed;
    }
    .list{
      width: 100%;
      height: 100%;
    }
    .header{
      position: relative;
      height: 34px;
      line-height: 34px;
      text-align: center;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
      border-bottom: 1px solid #e9e9e9;
      background-color: #fff;
      color:#000;
    }
    .prevBtn, .nextBtn{
      position: absolute;
      top: 0;
      color: #000;
      font-family: Arial, "Hiragino Sans GB", "Microsoft Yahei", "Microsoft Sans Serif", sans-serif;
      padding: 0 5px;
      font-size: 16px;
      display: inline-block;
      line-height: 34px;  
      height: 100%;  
      &:hover{
        &::before, &::after{
          border-color: rgba(0, 0, 0, 0.65);
        }
      }
      &::before, &::after{
        position: relative;
        top: -1px;
        display: inline-block;
        width: 8px;
        height: 8px;
        vertical-align: middle;
        border: 0 solid #aaa;
        border-width: 1.5px 0 0 1.5px;
        border-radius: 1px;
        transform: rotate(-45deg) scale(0.8);
        transition: all 0.3s;
        content: '';
      }
      &::after{
        left:-3px
      }
    }
    .nextBtn{
      &::before,&::after{
        transform: rotate(135deg) scale(0.8);
      }
    }
    .prevBtn{
      left:7%;
    }
    .nextBtn{
      right:7%;
    }
    .body{
      height: calc(100% - 34px);
      background-color: #fff;
    }
    .yearUl{
      padding: 0;
      margin: 0;
      overflow: hidden;
      list-style: none;
      li{
        float: left;
        width: 33.33%;
        max-width: 76px;
        text-align: center;
        cursor: pointer;
        button{
          cursor: pointer;
          outline: none;
          border: 0;
          display: inline-block;
          margin: 0 auto;
          color: rgba(0, 0, 0, 0.65);
          background: transparent;
          text-align: center;
          height: 24px;
          line-height: 24px;
          padding: 0 6px;
          border-radius: 4px;
          transition: background 0.3s ease;
          margin: 14px 0;
        }
      }
    }
    li.calendarYearSelected{
      button{
        background-color: #108ee9;
        color: #fff;
      }
    }

    使用组件的页面 jsx 文件。

    import React from 'react'
    import moment from 'moment'
    
    import YearPicker from './yearPicker/myYearSelect'
    
    class yaerSelectPageNew extends React.Component {
      constructor(props){
        super(props)
        this.state = {
          mockData:{
            year:2020
          },
          YPWidth:231
        }
      }
    
      filterByYear = (e) => {
        const { mockData } = this.state
        this.setState({mockData: {
          ...mockData,
          year: e.toString()
        }});
      }
    
      render(){
        const { YPWidth, mockData } = this.state
    
        return (
          <div>
            
            <h1>Page </h1>
            <div style={{  '200px' }}>
              <YearPicker 
              defaultValue={moment().format('YYYY')} 
              callback={this.filterByYear} 
              width={YPWidth}
              />
            </div>
          </div>
        );
      }
    }
    
    export default yaerSelectPageNew
  • 相关阅读:
    886C. Petya and Catacombs#墓室探险(set集合)
    uc/os调度机制深度解析
    总结使用QObject实现线程
    日常总结--c++常量的深入理解
    数据结构与算法--跳跃链表
    java下输出中文的一点研究
    java使用readUTF()读取中文抛出EOFException异常的处理方法
    java连接5.1以上的mysql出现问题---The server time zone value '???ú±ê×??±??' is unrecognized or represents more than one time zone.
    Qt入门便遇到坑--向QMainWindow类及其子类中添加布局
    linux_4.19内核编译总结
  • 原文地址:https://www.cnblogs.com/foxcharon/p/12318578.html
Copyright © 2011-2022 走看看