IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> react+dva页面上滑加载数据功能 -> 正文阅读

[JavaScript知识库]react+dva页面上滑加载数据功能

react+dva实现页面上滑加载数据功能

场景: 原PC页面分页展示的数据,现在为了用户使用方便,支持手机端就能随时查看;也就是说把本来PC展示的内容按照移动端的要求移植到手机上。于是老后端为了提高开发效率、节约开发成本,直接把原PC端分页接口甩在了我的脸上(这种情况基本上会经常碰到)。很多情况下前后端
要做的功能是可以互相甩的,就看谁理由逼格高、语气态度硬。当然我是那种热爱和平的人,如果别人嗯嗯啊啊推辞不愿做而自己又能做的事就不会去争的面红耳赤,毕竟代码敲的越多自身的收益也就越大,一味的甩锅和逃避就会失去很多提升自己的机会。

言归正传,本次的需求也很简单只要前端将分页展示的每页条数改成很大值,就可以拿到所有后台返回的数据了;但这样一来前端会出现一个问题,如果后台返回的数据量少三五十条还好,如果是三五百条或者更多,全部展示的时候手机就会出现明显的卡顿,针对这个问题前端可定要做类似PC那种分页效果:默认展示几条,在浏览完默认条数往下滑动的时候依次展示剩下内容即可。

实现思路: 进入页面,调用接口拿到全部数据,默认展示n条(本例中展示5条);在页面初次加载完毕后获取展示区域的DOM,给目标区域添加一个scroll滚动事件,每次触发滚动时把滚动的高度、目标区域高度之和与内容的scrollHeight进行比较;当前者等于后者时,表示内容已经滑动到了底部,此时将展示的数据源加上下一页的数据,重复此步骤直至展示全部数据。

步骤代码:

  1. 拿到数据,按分页的思路处理数据:
async componentDidMount(){
    const { dispatch } = this.props;
    await dispatch({
      type: 'dynamicLoading/fetchDataList',
      payload: {pageSize: 999999} // 本地mock数据模仿
    });
    const { currentSize } = this.state; // 当前页面展示的条数,demo默认为5
    const { dynamicLoading } = this.props; // 所有数据
    if(currentSize === 0) return;
    // 数据源处理
    let tempList = mapListHandleFunc(dynamicLoading.dataInfo, currentSize);
    this.setState({displayList: tempList, dataList: dynamicLoading.dataInfo});
    const domNode = this.contentRef.current; // 获取DOM 并添加scroll事件
    if(domNode){
      domNode.addEventListener('scroll', this.onScrollFunc);
    }
  }

mapListHandleFunc方法将总数据按条件的进行截取:

function mapListHandleFunc(listData=[],size=0){
  let tempList = [];
  for(let i=0;i<listData.length;i++){
    if(i>=size){
      break;
    }
    tempList.push(listData[i]);
  }
  return tempList;
}
  1. 上滑判断数据加载(核心):
onScrollFunc=()=> {
    const domNode = this.contentRef.current;
    const clientHeight = domNode.clientHeight;
    const scrollHeight = domNode.scrollHeight;
    const scrollTop = domNode.scrollTop;
    const { currentSize, flag, dataList } = this.state;
    if(scrollTop+clientHeight >= scrollHeight && !flag){// 每次滑动判断是否到了底部
      this.setState({scorollLoading: true});
      if(currentSize >= dataList.length) { // 判断是否已经展示了所有数据
        this.timeoutFunc = setTimeout(() => {
          this.setState({scorollLoading: false, flag: true});
        }, 1000);
        return
      }
      this.timeoutFunc = setTimeout(() => { // 每次上滑到底部添加下一页数据
        let tmepCurrentSize = currentSize + 5;
        let tempDisplayList = mapListHandleFunc(dataList, tmepCurrentSize);
        this.setState({ scorollLoading: false, currentSize: tmepCurrentSize, displayList:tempDisplayList});
      }, 1000);
    }
  } 
  1. 展示页面全部代码:
import React, { Component } from 'react';
import { connect } from 'dva';
import { ActivityIndicator} from 'antd-mobile';
import moment from 'moment';
import { routerRedux } from 'dva/router';
import styles from './index.less';

class DynamicPage extends Component {
  contentRef = React.createRef();
  state = {
    scorollLoading: false,
    currentSize: 5,
    displayList: [],
    flag: false,
    dataList: []
  }
   async componentDidMount(){
    const { dispatch } = this.props;
    await dispatch({
      type: 'dynamicLoading/fetchDataList',
      payload: {}
    });
    const { currentSize } = this.state;
    const { dynamicLoading } = this.props;
    if(currentSize === 0) return;
    let tempList = mapListHandleFunc(dynamicLoading.dataInfo, currentSize);
    this.setState({displayList: tempList, dataList: dynamicLoading.dataInfo});
    const domNode = this.contentRef.current;
    if(domNode){
      domNode.addEventListener('scroll', this.onScrollFunc);
    }
  }

  componentWillUnmount(){
    const domNode = this.contentRef.current;
    domNode.removeEventListener('scroll', this.onScrollFunc);
    clearTimeout(this.timeoutFunc);
  }

  onScrollFunc=()=> {
    const domNode = this.contentRef.current;
    const clientHeight = domNode.clientHeight;
    const scrollHeight = domNode.scrollHeight;
    const scrollTop = domNode.scrollTop;
    const { currentSize, flag, dataList } = this.state;
    if(scrollTop+clientHeight >= scrollHeight && !flag){
      this.setState({scorollLoading: true});
      if(currentSize >= dataList.length) {
        this.timeoutFunc = setTimeout(() => {
          this.setState({scorollLoading: false, flag: true});
        }, 1000);
        return
      }
      this.timeoutFunc = setTimeout(() => {
        let tmepCurrentSize = currentSize + 5;
        let tempDisplayList = mapListHandleFunc(dataList, tmepCurrentSize);
        this.setState({ scorollLoading: false, currentSize: tmepCurrentSize, displayList:tempDisplayList});
      }, 1000);
    }
  } 

  detailFunc=(id)=>{
    const { dispatch } = this.props;
    dispatch(routerRedux.push(`/detail?id=${id}`))
  }

  render(){
    const { scorollLoading, displayList, flag } = this.state;
    return (
      <div className={styles.home}>
        <div className={styles.header}>
          <span className={styles.headerAnimation}> 滑动加载数据功能演示 </span>
        </div>
        <div className={styles.content} ref={ this.contentRef } >
          {
            displayList.map((item, i) => (
              <div className={styles.listItem} key={ i }>
                <div className={styles.itemTitle}>
                  <div className={styles.title}>
                    <span>{ item.title }</span>
                    <span className={styles["t-detail"]} onClick={()=>this.detailFunc(item.id)}>详情</span>
                  </div>
                  <p className={styles.time}>{moment(item.time).format('YYYY-MM-DD HH:mm:ss')}</p>
                  <div  className={styles.border} />
                </div>
                <div className={styles.itemDetail}>
                  <div className={styles.detail}>
                    <div className={styles.label}>申请方</div>
                    <div className={styles.value}>{ item.purchers }</div>
                  </div>
                  <div className={styles.detail}>
                    <div className={styles.label}>申请类型</div>
                    <div className={styles.value}>{ item.type }</div>
                  </div>
                  <div className={styles.detail}>
                    <div className={styles.label}>地区</div>
                    <div className={styles.value}>{ item.area }</div>
                  </div>
                </div>
              </div>
            ))
          }
          {
            flag&&<div className={styles.scrollToBottomClass}>————嘤嘤嘤~没有更多啦~————</div>
          }
          <ActivityIndicator
            toast
            animating={ scorollLoading }
          />
        </div>
        <div className={styles.footer}></div>
      </div>
    )
  }
}

const mapStateToProps = ({dynamicLoading, loading})=>{
  return {dynamicLoading, gloabalLoading: loading.global, dymLoading: loading.effects['dynamicLoading/fetchDataList']};
}

export default connect(mapStateToProps)(DynamicPage);

function mapListHandleFunc(listData=[],size=0){
  let tempList = [];
  for(let i=0;i<listData.length;i++){
    if(i>=size){
      break;
    }
    tempList.push(listData[i]);
  }
  return tempList;
}

最终展示效果如下:

在这里插入图片描述

The end~

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 11:32:24  更:2021-07-29 11:33:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 8:37:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码