index.js 9.59 KB
/**
 * Created by gaoju on 2019/7/2.
 * 滚动组件
 * 注意:::此组件需要包裹在有高度的元素中,否则占满全屏
 */

import React, { Component } from 'react';
import IScroll from 'iscroll/build/iscroll-probe'
import styles from './index.css'

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      yesDown: false, // 是否已到了下拉刷新的高度
      yesUp: false, // 是否已到了上拉加载的高度
      loadingDownShow: false, // 是否处于刷新中状态
      loadingUpShow: false, // 是否属于加载中状态
      loadingDirection:'',//true 为下拉,false为上拉
      loadingEnd:false,//
      options: {
        backgroundColor: '#f5f5f5', // 背景颜色
        fontColor: '#888888', // 文字颜色
        beyondHeight: 50, // 超过此长度后触发下拉或上拉,单位px
        pulldownInfo: '下拉刷新',
        pulldownReadyInfo: '松开刷新',
        pulldowningInfo: '刷新中…',
        pulldownEnd:"刷新完成",
        pullupInfo: '上拉加载',
        pullupReadyInfo: '松开加载',
        pullupingInfo: '加载中…',
        pullupEnd:"没有新的数据了…",
      },
      boxHeight: 0,
      dataEnd:false,
      backTopFlag:false,
    };
    this.myScroll = null;
    this.timerRefresh = null; // 刷新iscroll的延时timer
    this.iscrollTimer = null; // 检测高度变化的timer
    this.elementToTarget = this.elementToTarget.bind(this);
  }
  componentDidMount() {
    console.log('------componentDidMount-------------')
    let options = {
      mouseWheel: true, //鼠标事件
      click: true,//点击事件
      probeType: 3,
      fadeScrollbars:false,
      scrollbars: false,
      //shrinkScrollbars: 'clip',//根据滚动缩放大小
      //fadeScrollbars: true,//滚动条淡入淡出
      //interactiveScrollbars:true,//滚动条能拖动
      //bounce:true,//滚动边缘反弹
    }
    // this.myScroll = new IScroll('#wrapper',options);
    let id = this.props.id + "_wrapper_scroller";
    this.myScroll = new IScroll("#"+id, Object.assign({}, options, this.props.iscrollOptions));
    
    this.myScroll.on('scroll', () => {
        const myScroll = this.myScroll;
         if (myScroll.y >0 && myScroll.y < this.state.options.beyondHeight) {
          this.setState({
            loadingDownShow: false,
            loadingUpShow: false,
          });
        }else if (myScroll.y > this.state.options.beyondHeight) {
          this.setState({
            loadingDirection:'down',
            loadingDownShow: true,
            loadingUpShow: false,
          });
        }else if (myScroll.y < -(this.state.options.beyondHeight)) {
          this.setState({
            loadingDirection:'down',
          });
        }else if (myScroll.y < myScroll.maxScrollY - this.state.options.beyondHeight) {
          this.setState({
            loadingDirection:'up',
            loadingDownShow: false,
            loadingUpShow: true,
          });
        }
      });
      this.myScroll.on('scrollStart', () => {
        window.top.addEventListener('mouseup', this.onMouseUpListener, false);
        window.top.addEventListener('touchend', this.onMouseUpListener, false);
      });

      this.myScroll.on('scrollEnd', () => {
        const myScroll = this.myScroll;
        if (myScroll.y > -100) {
          this.setState({
            backTopFlag:false
          });
        }else if (myScroll.y < -100) {
          this.setState({
            backTopFlag:true
          });
        }
      });

       this.setState({
          data: this.props.children,
          options: Object.assign({}, this.state.options, this.props.options),
        });
    let scrollDom = document.getElementById(id);
    scrollDom.addEventListener('touchmove', function (e) { e.preventDefault(); }, { passive: false });
    //绑定父组件得方法
    if(this.props.onRef){
        this.props.onRef(this)
    }
  }
  
  /** children内容改变时触发,表示已完成了刷新或加载 **/
  static getDerivedStateFromProps(nextP, prevState) {
        if (nextP.children != prevState.data) {
          console.log('------getDerivedStateFromProps--------更新-----')
            return {
                data: nextP.children,
                loadingDownShow: false,
                loadingUpShow: false,
                dataEnd: nextP.dataEnd ? true : false,
            };
        }
        return null;
  }
  componentDidUpdate(prevP, prevS){
      if(prevS.data !== this.state.data || prevP.hasDown !== this.props.hasDown || prevP.hasUp !== this.props.hasUp) {
        console.log('------componentDidUpdate--------onRefresh-----')
        // if(this.state.loadingDirection == 'down'){
        //    this.myScroll.scrollTo(0, this.myScroll.y);
        // }
        this.onRefresh();
      }
  }
  /** 组件即将销毁时触发,销毁当前iscroll实例 **/
  componentWillUnmount() {
    console.log('------componentWillUnmount--------destroy-----')
    //window.clearTimeout(this.iscrollTimer);
    this.myScroll.destroy();
  }

  /** 刷新ISCROLL **/
  onRefresh() {
    const myScroll = this.myScroll;
    window.clearTimeout(this.timerRefresh);
    this.timerRefresh = window.setTimeout(() => {
      myScroll.refresh();
    }, 200);
  }
  //锚点跳转
  elementToTarget(target){
    this.myScroll.scrollToElement(document.querySelector("#"+target))
  }
  onMouseUpListener = () => {
      const t = this;
      let maxScrollY = t.myScroll.maxScrollY;
      window.top.removeEventListener('mouseup', t.onMouseUpListener, false);
      window.top.removeEventListener('touchend', t.onMouseUpListener, false);
      // 如果滑动距离超过了设定界限并且当前没在下拉中,就触发下拉
      if(t.myScroll.y >= t.state.options.beyondHeight) {
          if(t.props.hasDown && t.props.onPullDownLoadMore) {
                //t.myScroll.scrollTo(0, t.myScroll.y);
                if (t.props.onPullDownLoadMore) {
                  this.props.onPullDownLoadMore();//加载新的数据
                }
          }

      } else if (t.myScroll.y < t.myScroll.maxScrollY - t.state.options.beyondHeight) {
        console.log('---onMouseUpListener------->>>>',t.myScroll.y,t.myScroll.maxScrollY,t.props.dataEnd,t.state.dataEnd)
         if(t.props.hasUp && t.props.onPullUpLoadMore) {
                if (t.props.onPullUpLoadMore) {
                    this.props.onPullUpLoadMore();//加载新的数据
                }
          }
      }
    };
  render() {
    let {data,backTopFlag} = this.state;
    let id = this.props.id + "_wrapper_scroller";
    return (
      <div id={id} className={styles.wrapper_scroller}  >
        <div className={styles.scroller}>
          <div className={styles.scroller_pullDown} style={{ display: !this.props.hasDown ? 'none' : 'inline-block' }}>
            {
              this.state.loadingDownShow ? (
                <div className={styles.loadingSection}>
                  <img src={require('./assets/loading.gif')} />
                  <span className = {styles.msg} style={{ color: this.state.options.fontColor, display: 'inline-block' }}>
                    {this.state.options.pulldowningInfo}
                  </span>
                </div>
              ) : (
                <div>
                  <span className = {styles.msg} style={{ color: this.state.options.fontColor, display: 'inline-block' }}>
                  {this.state.options.pulldownInfo}
                  </span>
                </div>
              )
            }
          </div>
          <div>
            {this.props.children}
          </div>
          <div className={styles.scroller_pullUp} style={{ display: !this.props.hasUp ? 'none' : 'inline-block' }}>
            {this.state.backTopFlag &&(
                  !this.state.dataEnd ? (
                    <div className={styles.loadingSection}>
                      <img src={require('./assets/loading.gif')} />
                      <span className = {styles.msg} style={{ color: this.state.options.fontColor, display: 'inline-block' }}>
                        {this.state.options.pullupingInfo}
                      </span>
                    </div>
                  ) : (
                    <div className={styles.loadingSection}>
                      <span className = {styles.msg} style={{ color: this.state.options.fontColor, display: !this.props.hasUp ? 'none' : 'inline-block' }}>
                      {this.props.finishStr || this.state.options.pullupEnd}
                      </span>
                    </div>
                  )
              )
            }
          </div>
        </div>
        {this.props.haveBackTop && (
            <div style={{ display: backTopFlag ? 'block' : 'none'}} className={styles.backTopSection} onClick={()=>{this.myScroll.scrollTo(0,0,600)}}>
              <img src={require("../../assets/image/backTop.png")} />
            </div>
          )}
      </div>
    );
  }
}

export default Home;
/**
 * 
 id: PropTypes.string,                 // id
 children: PropTypes.object,           // 数据
 options: PropTypes.object,            // 自定义参数
 iscrollOptions: PropTypes.object,     // iscroll原生参数
 detectionHeight: PropTypes.bool,      // 是否不停的检测高度变化
 className: PropTypes.string,          // 额外的class
 onPullDownLoadMore: PropTypes.func,    // 下拉刷新
 onPullUpLoadMore: PropTypes.func,     // 上拉加载更多
 hasDown:PropTypes.bool,// 是否有下拉加载
 hasUp:PropTypes.bool,// 是否有上拉加载更多
 noDownStr:PropTypes.string,// 加载完提示
 noUpStr:PropTypes.string,// 刷新完提示
 finishStr:PropTypes.string,// 加载完成提示语
 haveBackTop:PropTypes.bool,// 是否又返回顶部按钮
 * 
 **/