React组建实现新闻下拉刷新加载

React组建实现新闻下拉刷新加载_第1张图片
新闻列表格式

整体布局:




    
    ListView 2
    
    
    
    
    


    

首先需要引入React基础库,dom库,jsx解析库和移动端Jquery库(用于动态请求异步加载数据),然后创建一个Div,引入自己的组建。
整个应用组件

var App = React.createClass({
    getInitialState: function () {
        return {
            page: 1,
            article: [],//文章列表
        };
    },
    componentDidMount: function () {//组件被加载之后,默认加载第一页数据
        this.getData(1);
    },
    onRefresh: function () {//下拉刷新函数
        this.setState({page: 1});
        this.getData(this.state.page);
    },
    onLoadMore: function () {//加载更多函数
        var page = this.state.page + 1;
        console.log(page)
        this.setState({page: page});
        this.getData(page);
    },
    getItem: function (article) {
        return ;
    },
    getData: function (page) {//获取数据的函数
        var self = this;
        $.ajax({
            url: "http://wangyi.butterfly.mopaasapp.com/news/api?
                  type=travel&page=" + page + "&limit=5",
            type: 'GET',
            success: function (data) {
                // 4.对data进行处理,并进行对应的dom渲染
                if (page == 1) {//如果是第一页,直接覆盖之前的数据
                    self.setState({article: data.list})
                  //父组件的setState  改变的自己的状态的同时触发了自组件
                      的componentWillReceiveProps
                   // 子组件可以在componentWillReceiveProps里接受新的参
                      数,改变自己的state会自动触发render渲染
                } else {
                    self.setState({//否则累加数组
                        article: self.state.article.concat(data.list)
                    })
                }
            },
            error: function () {
                // 4.错误处理
            }
        })
    },
    render: function () {
        return (
            
        );
    }
});

解析:
1、首先对于组建进行初始化状态设置,当组建被加载后,默认加载第一页数据;
2、当进行下拉刷新时,设置状态为第一页并获取第一页数据;
3、当上拉加载更多时,状态为下一页,并获取下一页的数据。
通过Ajax获取新闻数据,对Data进行相应的处理,并进行对应的dom渲染。
** 渲染整个app**

  ReactDOM.render(
        ,
    document.getElementById('app')
);

** 静态常量**

var XLJZ = '下拉加载';
var SKJZ = '松开加载';
var JZ = '加载中...'
var dropDownRefreshText = XLJZ;
var dragValve = 40; // 下拉加载阀值
var scrollValve = 40; // 滚动加载阀值

子列表项组件,只负责渲染外面传递给他的数据(css设计样式)

var Item = React.createClass({
    render: function () {
        return (
  • {this.props.article.title}

    {this.props.article.time}

    {this.props.article.docurl}
  • ) } });

    ** 列表组件**

    var ListView = React.createClass({
        getInitialState: function () {//初始化状态
            return {
                translate: 0,//位移
                dragLoading: false,//是否在下拉刷新中
                scrollerLoading: false,//是否在加载更多中
                openDragLoading: true,//是否开启下拉刷新
                openScrollLoading: true,//是否开启下拉刷新
                data: []//默认的列表空数据
            };
        },
        componentDidMount: function () {//组建加载完毕,进行初始化赋值
            this.setState(
                {
                    translate: 0,
                    openDragLoading: this.props.openDragLoading || true,//根据外面设置的开关改变自己的状态
                    openScrollLoading: this.props.openScrollLoading || true
                }
            );
    
            this.initRefresh();//初始化下拉刷新
            this.initScroll();//初始化滚动加载更多
        },
        initRefresh: function (defaults, options) {
            var self = this;//对象转存,防止闭包函数内无法访问
            var isTouchStart = false; // 是否已经触发下拉条件
            var isDragStart = false; // 是否已经开始下拉
            var startX, startY;        // 下拉方向,touchstart 时的点坐标
            var hasTouch = 'ontouchstart' in window;//判断是否是在移动端手机上
            // 监听下拉加载,兼容电脑端
            if (self.state.openDragLoading) {
                self.refs.scroller.addEventListener('touchstart', touchStart, false);
                self.refs.scroller.addEventListener('touchmove', touchMove, false);
                self.refs.scroller.addEventListener('touchend', touchEnd, false);
                self.refs.scroller.addEventListener('mousedown', touchStart, false);
                self.refs.scroller.addEventListener('mousemove', touchMove, false);
                self.refs.scroller.addEventListener('mouseup', touchEnd, false);
            }
            function touchStart(event) {
                if (self.refs.scroller.scrollTop <= 0) {
                    isTouchStart = true;
                    startY = hasTouch ? event.changedTouches[0].pageY : event.pageY;
                    startX = hasTouch ? event.changedTouches[0].pageX : event.pageX;
                }
            }
    
            function touchMove(event) {
                if (!isTouchStart) return;
                var distanceY = (hasTouch ? event.changedTouches[0].pageY : event.pageY) - startY;
                var distanceX = (hasTouch ? event.changedTouches[0].pageX : event.pageX) - startX;
                //如果X方向上的位移大于Y方向,则认为是左右滑动
                if (Math.abs(distanceX) > Math.abs(distanceY))return;
                if (distanceY > 0) {
                    self.setState({
                        translate: Math.pow((hasTouch ? event.changedTouches[0].pageY : event.pageY) - startY, 0.85)
                    });
                } else {
                    if (self.state.translate !== 0) {
                        self.setState({translate: 0});
                        self.transformScroller(0, self.state.translate);
                    }
                }
    
                if (distanceY > 0) {
                    if (!isDragStart) {
                        isDragStart = true;
                    }
                    if (self.state.translate <= dragValve) {// 下拉中,但还没到刷新阀值
                        if (dropDownRefreshText !== XLJZ)
                            self.refs.dropDownRefreshText.innerHTML = (dropDownRefreshText = XLJZ);
                    } else { // 下拉中,已经达到刷新阀值
                        if (dropDownRefreshText !== SKJZ)
                            self.refs.dropDownRefreshText.innerHTML = (dropDownRefreshText = SKJZ);
                    }
                    self.transformScroller(0, self.state.translate);
                }
            }
            function touchEnd(event) {
                isDragStart = false;
                if (!isTouchStart) return;
                isTouchStart = false;
                if (self.state.translate <= dragValve) {
                    self.transformScroller(0.3, 0);
                } else {
                    self.setState({dragLoading: true});//设置在下拉刷新状态中
                    self.transformScroller(0.1, dragValve);
                    self.refs.dropDownRefreshText.innerHTML = (dropDownRefreshText = JZ);
                    self.props.onRefresh();//触发冲外面传进来的刷新回调函数
                }
            }
        },
        initScroll: function () {
            var self = this;
            // 监听滚动加载
            if (this.state.openScrollLoading) {
                this.refs.scroller.addEventListener('scroll', scrolling, false);
            }
    
            function scrolling() {
                if (self.state.scrollerLoading) return;
                var scrollerscrollHeight = self.refs.scroller.scrollHeight; // 容器滚动总高度
                var scrollerHeight = self.refs.scroller.getBoundingClientRect().height;// 容器滚动可见高度
                var scrollerTop = self.refs.scroller.scrollTop;//滚过的高度
                // 达到滚动加载阀值
                if (scrollerscrollHeight - scrollerHeight - scrollerTop <= scrollValve) {
                    self.setState({scrollerLoading: true});
                    self.props.onLoadMore();
                }
            }
        },
        /**
         * 利用 transition 和transform  改变位移
         * @param time 时间
         * @param translate  距离
         */
        transformScroller: function (time, translate) {
            this.setState({translate: translate});
            var elStyle = this.refs.scroller.style;
            elStyle.webkitTransition = elStyle.MozTransition = elStyle.transition = 'all ' + time + 's ease-in-out';
            elStyle.webkitTransform = elStyle.MozTransform = elStyle.transform = 'translate3d(0, ' + translate + 'px, 0)';
        },
        /**
         * 下拉刷新完毕
         */
        dragLoadingDone: function () {
            this.setState({dragLoading: false});
            this.transformScroller(0.1, 0);
        },
        /**
         * 滚动加载完毕
         */
        scrollLoadingDone: function () {
            this.setState({scrollerLoading: false});
            this.refs.dropDownRefreshText.innerHTML = (dropDownRefreshText = XLJZ);
        },
        /**
         * 当有新的属性需要更新时。也就是网络数据回来之后
         * @param nextProps
         */
        componentWillReceiveProps: function (nextProps) {
            var self = this;
            this.setState({data: nextProps.article,});//把新的数据填进列表
            if (this.state.dragLoading) {//如果之前是下拉刷新状态,恢复
                setTimeout(function () {
                    self.dragLoadingDone();
                }, 1000);
            }
            if (this.state.scrollerLoading) {//如果之前是滚动加载状态,恢复
                setTimeout(function () {
                    self.scrollLoadingDone();
                }, 1000);
            }
        },
        render: function () {
            var self = this;
            return (
                    

    下拉加载

      {self.state.data.map(function (item) {//通过map循环把子列表数据展示出来 return self.props.getItem(item); }) }
    加载中...
    ); } });

    列表组建下拉刷新解析:
    1、通过refs找到滚动的容器scroller,给它添加监听事件,为了兼容电脑端和移动端,需要监听触摸事件和鼠标事件;
    2、当触摸开始或鼠标按下时,回调touchstart函数,判断是否滚动到容器顶端,如果滚动到顶端,再判断是否是手机触摸事件,是就记录第一个触摸点的X,Y值,不是就记录电脑鼠标按下的位置;
    3、当触摸移动或鼠标移动时,回调touchMove函数,判断是否是触摸状态,同时记录下触摸移动的距离(如果X方向上的位移大于Y方向,则认为是左右滑动并返回):

    • 判断Y方向的位移是否大于0,如果大于0,滚动容器的位移取触摸位移的0.85次方,当触摸位移过大时,容器的位移到达一定值就不再跟随;
    • 当Y方向的位移大于0时,确定开始拖拽;滚动容器在下拉中,但还没到刷新阀值时,显示“下拉加载”;已经达到刷新阀值,显示“松开加载”;

    4、当触摸结束或鼠标抬起时,回调touchEnd函数。若滚动容器在下拉中,但还没到刷新阀值,经过0.3S位移回到0;若已经达到刷新阀值,经过0.1s位移为刷新阀值,显示“加载”,并触发冲外面传进来的刷新回调函数;
    列表组建加载更多解析:
    1、监听滚动加载:当滚动容器滚动时,回调滚动加载函数;
    2、如果是滚动加载状态则返回;
    3、当容器滚动总高度- 容器滚动可见高度-滚过的高度小于滚动加载阀值时,设置滚动加载状态,触发从外面传进来的加载更多回调函数。
    列表下拉跟随解析:
    transformScroller(time, translate)传入两个参数:时间和距离;
    利用 transition 和transform 改变位移,transition 属性设置 'all ' + time + 's ease-in-out'表示过渡阶段慢快慢;
    transform 属性设置'translate3d(0, ' + translate + 'px, 0)'位移过程更流畅;

    当有新的属性需要更新时,也就是网络数据回来之后,把新的数据填进列表;如果之前是下拉刷新状态,恢复;如果之前是滚动加载状态,恢复。
    最后渲染列表组建,通过map循环把子列表数据展示出来。
    效果图如下:


    React组建实现新闻下拉刷新加载_第2张图片
    下拉加载

    React组建实现新闻下拉刷新加载_第3张图片
    松开加载

    React组建实现新闻下拉刷新加载_第4张图片
    刷新加载中

    React组建实现新闻下拉刷新加载_第5张图片
    上滑加载更多

    你可能感兴趣的:(React组建实现新闻下拉刷新加载)