React上拉加载和下拉刷新

9 篇文章 0 订阅

最近在做一个功能,就是上拉加载下一页,用的是react搭建前端视图,以下是我的做法和遇到的相关问题及解决办法:

案例一:回到顶部

class Home extends Component {
 consrcutor(props) {
    super(props);
    this.state={
        showScroll: false
    }
 }
 componentDidMount() {
    this.bindEvent();
  }

  componentWillUnmount() {
    window.removeEventListener("scoll", this.props.toggleTopShow);
  }


  bindEvent = () => {
    window.addEventListener("scroll", this.props.toggleTopShow);
  };

  toggleTopShow = () => {
      let showScroll = '';
      if (document.documentElement.scrollTop > 100) {
         showScroll = true;
      } else {
         showScroll = false;
      }
      
      this.setState({
          showScroll
      });
   }
  
  handleScrollTop = () => {
    window.scrollTo(0, 0);
  };

  
  render() {
    return (
      <div>
        {this.state.showScroll ? (
          <BackTop onClick={this.handleScrollTop}>
            <i className="iconfont ic-backtop">&#xe66a;</i>
          </BackTop>
        ) : null}
      </div>
    );
  }
}

案例二:上拉加载下一页

页面布局说明:页面:banner+nav+content(页面高度100%,除了banner+nav固定外,剩余高度都是content,其content在其区域内随着内容增多是可以滚动的)

根据上面说明知道:页面整体不滚动,只是页面的局部区域滚动,所以不能将scroll绑定到window上而是content上,如下:

class Pool extends PureComponent {
   constructor(props) {
    super(props);
    this.state = {
      PullLoadingTip: ""
    };

    this.isLock = true;
    this.PoolCon = React.createRef();
    this.ParentCon = React.createRef();
    this.scrollToBottom = this.scrollToBottom.bind(this);
  }
    
  componentDidMount() {
    this.ParentCon.current.addEventListener("scroll", this.scrollToBottom);
  }

  componentWillUnmount() {
    this.ParentCon.current.removeEventListener("scroll", this.scrollToBottom);
  }

  scrollToBottom(event) {
    event.stopPropagation();

    const parent = this.ParentCon.current; //event.target;
    let scrolltop = parent.scrollTop;  //content上部滚动出的高度
    let height = Zepto(parent).height();  //content的固定高度
    let scrollheight = this.PoolCon.current.scrollHeight;  //content内部内容的高度
   
    if (scrollheight <= scrolltop + height) {
      console.log("到底了");
      if (Math.ceil(this.TOTAL / LIMIT) >= this.PAGE + 1) { //有下一页才执行可以加载
        this.setState(
          {
            isShowPullLoading: true
          },
          () => {         
            if (this.isLock) {  //请求下一页过程中不在发送请求
              this.getData();
            }
          }
        );
      }
    }
  }

  getData(flag) {
    this.isLock = false
    //发送请求获取下一页数据,成功后this.isLock改为true
 }
    
  render() {
    return (
      <article className="content">
        <section ref={this.PoolCon}>
          {/*content列表内容*/}
          {this.state.isShowPullLoading ? (
            <p className="pull-loading">正在加载...</p>
          ) : (
            ""
          )}
        </section>
      </article>
    );
  }
}

问题:上面两个案例均在componentDidMount()中均绑定了scroll事件,但是绑定到window上功能正常,绑定到某个元素上只有第一次有效,之后就不会再出发scroll事件。

解决:在元素上直接添加onScroll事件,而不是在componentDidMount()中绑定。修改如下:

//去掉this.ParentCon = React.createRef();

//<article className="content" onScroll={this.scrollToBottom}>...</article>

//scrollToBottom中:const parent = event.target;

案例三:移动端上实现上拉加载下一页

网上有很多插件如iscroll、better-scroll、http://www.htmleaf.com/jQuery/jquery-tools/201905275664.html等,可以看看(未实测),但是我的需求要求不高,没有搜索react相关插件, 就是用上面的原理实现的。

移动端一般不监听scroll事件,所以将绑定的事件改为touchstart、touchmove、touchend

touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。

touchmove事件:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用preventDefault()事件可以阻止滚动。

touchend事件:当手指从屏幕上离开的时候触发。

touchcancel事件:当系统停止跟踪触摸的时候触发。关于这个事件的确切出发时间,文档中并没有具体说明,咱们只能去猜测了。

问题:移动端touch相关事件是绑定到元素上,还是生命周期componentDidMount函数中?

实际测试onTouchmove、onTouchend直接绑定到元素上,可以触发,但是很难触发;绑定到componentDidMount上功能正常,即直接在componentDidMount中将touch相关事件绑定到content上。

//再把 this.PoolCon = React.createRef();加回来

// <article className="content" ref={this.ParentCon}>...</article>

 componentDidMount() {
    this.ParentCon.current.addEventListener("touchmove", () => this.scrollToBottom(event, 1), { passive: false });
    this.ParentCon.current.addEventListener("touchend", () => this.scrollToBottom(event, 2));
  }

  componentWillUnmount() {
    this.ParentCon.current.removeEventListener("touchmove", () => this.scrollToBottom(event, 1));
    this.ParentCon.current.removeEventListener("touchend", () => this.scrollToBottom(event, 2));
  }


  scrollToBottom(event, type) {
    event.stopPropagation();

    const parent = this.ParentCon.current; //event.target;
    let scrolltop = parent.scrollTop;
    let height = Zepto(parent).height();
    let scrollheight = this.PoolCon.current.scrollHeight;

    if (scrollheight <= scrolltop + height) {
      if (Math.ceil(this.TOTAL / LIMIT) >= this.PAGE + 1) {
        if (1 === type) {
          this.setState({
            PullLoadingTip: "释放立即加载..."
          });
        } else if (2 === type) {
          this.setState(
            {
              PullLoadingTip: "正在加载..."
            },
            () => {
              if (this.isLock) {
                this.getData();
              }
            }
          );
        }
      }
    }
  }

案例四:移动端实现下拉刷新

因为没有需求,所以不是react版本

    <main class="parent">
        <p class="refreshText"></p>
        <ul id="refreshContainer">
            ...
            <li>111</li>
            ...
        </ul>
    </main>
window.onload = function(){
            //1.获取到列表的dom,刷新显示部分的dom,列表父容器的dom
            let container = document.querySelector('#refreshContainer');

            let refreshText = document.querySelector('.refreshText');

            let parent = document.querySelector('.parent');

 
            //2.定义一些需要常用的变量
            let startY = 0;//手指触摸最开始的Y坐标

            let endY = 0;//手指结束触摸时的Y坐标

            
            //3.给列表dom监听touchstart事件,得到起始位置的Y坐标
            parent.addEventListener('touchstart',function(e){
                startY = e.touches[0].pageY;

            });

            //4.给列表dom监听touchmove事件,当移动到一定程度需要显示上面的文字
            parent.addEventListener('touchmove',function (e) { 

                if(isTop() && (e.touches[0].pageY-startY) > 0){

                    console.log('下拉了');

                    refreshText.style.height = "50px";

                    parent.style.transform = "translateY(50px)";

                    parent.style.transition = "all ease 0.5s";

                    refreshText.innerHTML = "释放立即刷新...";

                }

            });


            //5.给列表dom监听touchend事件,此时说明用户已经松开了手指,应该进行异步操作了
            parent.addEventListener('touchend',function (e) { 

                if(isTop()){

                    refreshText.innerHTML = "正在刷新...";

                    setTimeout(function(){

                        parent.style.transform = "translateY(0)";

                        console.log('成功刷新');

                    },2000)

                }

                return;

            })


            function isTop(){
                var t = document.documentElement.scrollTop||document.body.scrollTop;
                return t === 0 ? true : false;
            }
        }

 

以上就是自己的做法,有问题可以留言,共同成长。

求告知好用的react相关组件库

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值