当前位置: 首页 > news >正文

React中使用LazyBuilder实现页面懒加载方法一

前言:

        在一个表格中,需要展示100条数据,当每条数据里面需要承载的内容很多,需要渲染的元素也很多的时候,容易造成页面加载的速度很慢,不能给用户提供很好的体验时,懒加载是优化页面加载速度的方法之一。

策略:

        前端在接受到api返回的数据的时候,可以先根据数据总的条数进行遍历,给每一项初始化简单的dom进行渲染占位,通过IntersectionObserver对每一项元素进行监听,当初始dom出现在页面视口的时候,需要替换掉初始dom,渲染真实dom,同样,在初始dom隐藏在页面视口后,我们再去替换掉真实dom,渲染初始dom。这样可以实现:只有出现在视口内的元素才渲染真实的dom,在视口以外的元素都渲染初始dom,首次加载多少个真实dom,取决于可视区域跟初始dom的高度

React中使用LazyBuilder实现页面懒加载方法二

与方法二不同之处:

方法一:元素出现在可视区域内,即渲染真实dom,一旦消失在可视区域内,即渲染初始dom

方法二:元素只要出现在可视区域内一次,即渲染真实dom,并且取消对该dom的监听,只需加载一次

LazyBuilder.jsx

import React, { Component, createRef } from "react";
class LazyBuilder extends Component {static defaultProps = {initComponent: null,initHeight: null,controller: null,className: null,style: null,}/*** @param {Object} props* @param {JSX.Element} [props.initComponent] - 默认组件* @param {Number} [props.initHeight] - 组件高度* @param {LazyController} [props.controller] - LazyController*/constructor(props) {super(props);this._ref = createRef();this.controller = this.props.controller instanceof LazyController ? this.props.controller : new LazyController();this.state = {isLoading: undefined,firstIsLoading: true, // 作用:在页面进行初始渲染时,所有的项都设置初始dominitStyle: {width: "100%",height: props.initHeight},key: `lazy_${Math.random().toString(16).slice(2)}`,}}componentDidMount() {// 页面初始化时,对所有元素进行绑定监听this.controller.observe(this._ref.current, this.updateShowElement.bind(this));}updateShowElement = (type) => {const {initHeight} = this.propsif(type == 1){// 元素出现在视口以内this.setState({isLoading: false,firstIsLoading: false,initStyle: null,});} else if(type == 2) {// 元素出现在视口以外this.setState({isLoading: true,initStyle: {width: "100%",height: initHeight},});}}render () {const { children, initComponent } = this.props;const { isLoading, initStyle, firstIsLoading} = this.state;const className = ["lazy-builder-item", this.props.className].filter(item => typeof item === "string").join("\s");return (<div id={this.state.key} ref={this._ref} className={className} style={Object.assign({}, initStyle, this.props.style)}>{firstIsLoading? initComponent: isLoading ? initComponent : children}</div>);}
}class LazyController {constructor(){// 定义map来存储所有的dom项this._map = new Map();// IntersectionObserver 对每一项元素进行监听this.observer = new IntersectionObserver((entries) => {for (const entry of entries) {const updateShowElement = this._map.get(entry.target);// isIntersecting: true - 出现在视口    false - 隐藏(视口以外)if (entry.isIntersecting) {if (typeof updateShowElement === "function") {updateShowElement(1)}} else {if (typeof updateShowElement === "function") {updateShowElement(2)}}}});}// 观察指定DOMobserve = (target, callback) => {if (this.observer && !this.has(target)) {// 初始化时,将每一项保存在map中this._map.set(target, callback);this.observer.observe(target);}}// 判断一个DOM是否正在被观察has = (target) => {return this._map.has(target);}}export {LazyBuilder,LazyController,
}

cp.jsx

import React, {Component} from 'react';
import { LazyBuilder, LazyController } from './LazyBuilder'
export default class  Cp extends Component {constructor(props){super(props)// 创建controllerthis.controller = new LazyController();this.state = {// 模拟数据dataList: new Array(100).fill().map((item, index) => index + 1)}}render(){const {dataList} = this.statereturn (<div>{Array.isArray(dataList) && dataList.length > 0? dataList.map((item, index) => {return <LazyBuilder key={index}initHeight={100} // 初始dom高度controller={this.controller} // controller><div style={{width: '100%', height: '200px'}}>{`第${item}个元素`}</div></LazyBuilder>}): null}</div>)}
}

效果

页面刚加载时,只有前面几条数据在视口内 

经过滚动后

相关文章:

  • 头歌C语言结构体
  • 【驱动】TI AM437x(内核调试-07):devmem2直接读写内存、寄存器,devkmem读取内核变量
  • Android 系统启动流程
  • 运维SRE-01 目录结构体系、find
  • Codeforces Round 921 (Div. 2)补题
  • ambari hdp 企业级安装实战
  • C语言之猜凶手
  • 04 Redis之命令(Hash型Value命令+List型Value命令+Set型Value命令+有序集合ZSET型Value命令)
  • MySQL必看表设计经验汇总-上(精华版)
  • Linux之常见的管理命令
  • java日志框架总结(三 、Log4j日志框架)
  • SQL注入-sqli-labs-master第一关
  • 微信生成带参数二维码(用户id), 扫码可获取用户id
  • 免费开源的微信小程序源码、小游戏源码精选70套!
  • Python一行命令搭建HTTP服务器并外网访问 - 内网穿透
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • Brief introduction of how to 'Call, Apply and Bind'
  • C++11: atomic 头文件
  • Java 网络编程(2):UDP 的使用
  • Java小白进阶笔记(3)-初级面向对象
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • nodejs:开发并发布一个nodejs包
  • PAT A1017 优先队列
  • Swift 中的尾递归和蹦床
  • Terraform入门 - 3. 变更基础设施
  • 安卓应用性能调试和优化经验分享
  • 分布式事物理论与实践
  • 正则表达式小结
  • 浅谈sql中的in与not in,exists与not exists的区别
  • # .NET Framework中使用命名管道进行进程间通信
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • ${ }的特别功能
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (第27天)Oracle 数据泵转换分区表
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (七)c52学习之旅-中断
  • (三) diretfbrc详解
  • (三)mysql_MYSQL(三)
  • (正则)提取页面里的img标签
  • (转)ORM
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .net core 连接数据库,通过数据库生成Modell
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net 无限分类
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • 。Net下Windows服务程序开发疑惑
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @JSONField或@JsonProperty注解使用
  • @RestController注解的使用
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [20150904]exp slow.txt