在React中引入IScroll插件作滚动

最近作一个H5项目,数据交互量比较大,不少页面都是从后台拿过来数据作一个列表显示,这天然就遇到了滚动。css

刚开始我直接使用css作法,直接添加overflow: scroll;但在微信端用户滑动会直接将整个页面拖动,露出顶部的域名和底部的黑色背景。用户反映体验很差,要改……好吧,本身动手。但这并非好改的,由于在React中都是构建的是虚拟DOM,直接操做DOM也会对性能有必定影响。这时候网上搜了一下,拿出一个解决方案,献出部分代码:react

  

import React from 'react';
import { render } from 'react-dom';
import Router from './app/router';
import '../common/css/base.styl';
import '../common/css/waaStyle.styl';
import '../common/css/page.styl';
var divDom = document.createElement('div');
divDom.setAttribute('id', 'wrap');

document.body.appendChild(divDom);
document.body.addEventListener("touchmove",function (e) {
    e.preventDefault();
},false);
render(<Router />, divDom);

这是在React的根页面下直接禁用touchmove事件,禁止用户touchmove,能够达到不出现域名和黑色边框的效果。微信

因为禁止touchmove事件,在须要列表滚动的地方,overflow:scroll;监听不到touchmove了,滑动变得无效,怎么解决呢?咱们能够在须要滚动的地方禁止冒泡事件:app

//首先要获取须要禁止冒泡事件的dom,因为React是构建虚拟的dom,能够这样拿到dom:ref= {(ref) => {this.dom = ref}};

componentDidMount () {
      this.dom.addEventListener("touchmove",function (e) {
        e.stopPropagation();
      },false);  
} 

//dom在页面挂载完成后,禁止冒泡事件。   

  加上这样的代码后,就会发现,整个页面仍然是禁止滑动,列表页能够正常滚动,可是,当列表滚动到底的时候,用户继续滑动,整个页面仍然会跟着滑动,又露出咱们不想看到的部分,感受好气呀……框架

冷静分析一下,这条路是走不通的,因为列表区域禁止了冒泡事件,那么用户只要在列表区域滑动,那么你在body上作的禁止滑动就是没有效果的!dom

  万般无奈下,我有搬来了个人老伙计:IScroll.js。之因此选他,由于他有一个很是有用的方法:refresh();我只要在componentDidMount中实例化Iscroll,而且在React数据更新后再次refresh就能够了。那么开始作了。性能

React框架中引入咱们想要的插件,只要这样作就行:ui

import Iscroll from "moudle/iscroll/Iscroll";

而后页面挂载完成后咱们进行实例化this

componentDidMount() {
  setTimout(function () {//因为手机性能的缘由,咱们在定时器里面进行实例化
    this.myIScroll = new IScroll("#dom",{
    mouseWheel: true,
    bounce: true,
    scrollbars: false,
});  
  },10);
}

一但React检测到数据有更新,他就会自动刷新页面,那么咱们这个时候须要从新刷新IScroll:spa

componentDidUpdate() {
  this.myIScroll.refresh();  
}

代码作到这里,咱们就会发现,即便禁止touchmove事件,咱们依然可使用滚动列表,问题完美解决!不过,此时客户大手一挥,指着咱们的滚动条,这个滚动条有点丑呀,能不能把它作得科技感一些……哎,数不清的星星,改不完的需求啊,不过,这个对于咱们无(xia)所(chui)不(niu)能(bi)的程序猿也是能够作得。在IScroll中,它的滚动条是由两个作了定位的div构成的,那么

咱们在实例化IScroll的时候参数中设置:

this.myIScroll = new IScroll("#dom",{
scrollbars: 'custom',//即scrollbars的值设置成字符串:“custom”便可
});

而后咱们在样式表中使用两个类名:

.iScrollIndicator和.iScrollVerticalScrollbar.iScrollLoneScrollbar写入样式,这样组成滚动条的两个div就能够长成咱们但愿的样子啦!
可是根据需求,有的列表很长,须要分页加载,那么就须要判断用户拖动后是否须要加载下一页的数据了。
基本的思路是,利用this.y获得向上移动的距离,用里面框的高度减去移动的距离,再减去外面框的高度,若是小于某一个高度,咱们去请求数据,以后从新渲染就好了。可是,我查阅了IScroll的相关代码,文档上并无写出内外两个框高度的接口,也曾经试着本身在源码里添加得到框高度的方法,可是在实例化后获取这个值总会有各类各样的问题。最后通过仔细研究IScroll源码,发现外面框的高度就是实例化后的:this.wrapperHeight,而里面框的高度就是:this.scrollerHeight,这样咱们减去this.y的绝对值后,就能够判断出是否须要加载新的数据了。给大爷们线上代码:
componentDidMount () {
        var self = this;
        const options = {
            preventDefault: false,
            zoom: false,
            mouseWheel: true,
            probeType: 3,
            bounce: true,
            scrollbars: true,
        };
        this.iScrollInstance = new IScroll(this.scrollContent,options);
        this.iScrollInstance.on('scrollEnd', function() {

            var shouldGet = this.scrollerHeight + this.y - this.wrapperHeight;//注意this.y必定是非正数,因此这里是加啦!

            if (shouldGet < 200 && this.directionY === 1 && !self.state.loading) { //我这里设置的临界值是200,即列表滚动结束后,若是里框的高度还有小于200px的内容没有显示过就会去加载新的数据。
                if(self.state.pageNo >= self.state.totalPage) {
                    Action.update({noMore: true});

                } else {
                    self.state.pageNo ++;
                    Action.getList({pageNo: self.state.pageNo});
                }
            }
        });
    }

作到这里,咱们利用IScroll想解决的需求均可以知足了……

相关文章
相关标签/搜索