IntersectionObserver实现小程序长列表优化

news2024/9/28 9:55:46

IntersectionObserver实现小程序长列表优化

关于 IntersectionObserver

思路

这里以一屏数据为单位【一个分页的10条数据,最好大于视口高度】,
监听每一屏数据和视口的相交比例,即用户能不能看到它
只将可视范围的数据渲染到页面上,其余的使用空白高度占位符代替,

可视范围可扩大到当前可视范围的上下两倍到三倍,减少滚动时留白现象

实现

大多数都是监听 scroll,结合防抖函数,来控制数据的渲染

这里我们使用小程序自带api,IntersectionObserver 来实现

小程序 IntersectionObserver

通过 IntersectionObserver 来监听可视范围内的元素,当元素进入可视范围时,将对应的数据渲染到页面上。

其返回的 intersectionRatio 为相交比例,大于0 说明进入可视范围,渲染真实数据,否则,渲染高度占位符

第一步

首先需要两个数组,一个用来存放真实数据,一个用来存放高度占位符数据

将原来的 storeList,改为二维数组,以一屏为单位进行分割

// Taro

// wholePageHeight和wholeStoreList不用放在state中,页面销毁时记得释放

// 高度占位符数据
let wholePageHeight = [];
// 真实数据
let wholeStoreList = [];

state = {
    // 当前页码
    pageCurrent: 0,
    // 渲染的数据
    storeList: [],
    // 高度占位符数据
    storeListPlaceholder: [],
    // ...
}

第二步

获取界面上的节点信息

保存所有的列表数据以及页面高度数据

每次数据请求完成,将列表数据push到 wholeStoreList 中,
然后将当前这一屏的数据放到对应页面的 pageCurrentstoreList 中,
setState后, 计算这一屏的高度,然后将其存放到 wholePageHeight

// Taro

// 分页获取列表数据
getList = async () => {
    // 接口请求数据
    const { pageCurrent } = this.state;
    const records = await api.getList({
        pageCurrent
    });
    // 分页累加
    pageCurrent++

    // 保存所有的列表数据
    wholeStoreList.push(records);
    // 设置当前这一屏的数据
    storeList[pageCurrent] = records;

    this.setState({
        storeList,
        pageCurrent,
    }, () => {
        // 数据setState后,获取当前页的高度
        this.getPageHeight();
    });
}

// 计算当前页的高度
getPageHeight = () => {
    const {
        pageCurrent,
    } = this.state;
    // 返回一个 SelectorQuery 对象实例
    const query = Taro.createSelectorQuery();
    // 查询节点信息的对象
    query
        // 在当前页面下选择第一个匹配选择器 selector 的节点。返回一个 NodesRef 对象实例,可以用于获取节点信息。
        // 类似于 CSS 的选择器
        .select(`#storePage${pageCurrent}`)
        // 添加节点的布局位置的查询请求,SelectorQuery.exec 方法后,节点信息会在 callback 中返回
        .boundingClientRect()
        // 执行所有的请求。请求结果按请求次序构成数组,在callback的第一个参数中返回。
        .exec(res => {
        if (res && res[0].height) {
            /**
             *   rect.id      // 节点的ID
             *   rect.dataset // 节点的dataset
             *   rect.left    // 节点的左边界坐标
             *   rect.right   // 节点的右边界坐标
             *   rect.top     // 节点的上边界坐标
             *   rect.bottom  // 节点的下边界坐标
             *   rect.width   // 节点的宽度
             *   rect.height  // 节点的高度
             */
            // 保存当前页的高度
            wholePageHeight.push(res[0].height);
            
            // 监听当前页的节点
            this.observePage(pageCurrent);
        }
    });
}

第三步

针对每一屏都去添加监听,判断是否需要渲染真实数据,还是高度占位符

这里通过 IntersectionObserver 来监听,当元素进入可视范围时,将对应的数据渲染到页面上。

:::tip 小细节

如果只控制一屏的显示,那么当用户快速滑动上下屏时,
会出现一屏的数据还没渲染完,就已经滚动到下一屏了,导致白屏出现

所以:需要设置 relativeToViewport top 和 bottom 参数,顶部和底部的边界,进入上下三个屏幕高度就开始渲染

:::

// Taro

observePage = () => {
    const {
        storeList,
    } = this.state;

    const windowHeight = Taro.systemInfo.windowHeight;

    // WXML节点布局相交状态
    // 创建 IntersectionObserver 对象,用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。
    const observerObj = Taro.createIntersectionObserver(this)
        // 指定页面显示区域作为参照区域之一
        .relativeToViewport({
            // 设置顶部和底部的边界,进入上下三个屏幕高度就开始渲染
            top: 3 * windowHeight, 
            bottom: 3 * windowHeight
        });
    
    // 返回IntersectionObserver对象实例,用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见
    observerObj.observe(`#storePage${pageIndex}`, (res) => {
        /**
         *   res.id // 目标节点 id
         *   res.dataset // 目标节点 dataset
         *   res.intersectionRatio // 相交区域占目标节点的布局区域的比例
         *   res.intersectionRect // 相交区域
         *   res.intersectionRect.left // 相交区域的左边界坐标
         *   res.intersectionRect.top // 相交区域的上边界坐标
         *   res.intersectionRect.width // 相交区域的宽度
         *   res.intersectionRect.height // 相交区域的高度
         */
        // < 0,未相交,使用高度占位符
        if (res.intersectionRatio <= 0) {
            storeList[pageIndex] = {
                height: wholePageHeight[pageIndex]
            }
            // > 0,相交,使用真实数据
        } else {
            storeList[pageIndex] = wholeStoreList[pageIndex];
        }
        this.setState({
            storeList
        });
    });
}

第四步

在页面上渲染数据,如果当前这一屏有数据,就渲染真实数据,否则渲染高度高度占位符


// Taro

// 列表渲染
renderStoreList = () => {
    const {
        storeList,
    } = this.state;
    return (
        storeList.map((storePage, index) => (
            <View className='store-page' key={index} id={'storePage' + index}>
                {
                    // 是否存在当前页的数据
                    storePage && storePage.length ?
                        <View className='store-list'>
                            {
                                storePage.map((storeItem) => (<StoreInfo item={storeItem} key={storeItem.id} />))
                            }
                        </View>
                        :
                        // 占位组件 ---
                        <PlaceWrap customStyle={{height: storePage.height + 'px'}} />
                }
            </View>
        ))
    )
};

到此,一个长列表的优化就OK了

IntersectionObserver

看了下 caniuse ,发现除了IE,兼容性也还行,那web端也可以尝试下的

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/808562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025年卡脖子技术清零?甚至计划推动鸿蒙欧拉比肩全球领先水平

深圳市工业和信息化局近日发布了推动开源鸿蒙欧拉产业创新发展的行动计划&#xff0c;以推动鸿蒙欧拉在2023至2025年期间成为全球领先操作系统&#xff0c;并构建全球信息技术体系&#xff0c;实现我国操作系统技术创新和自主发展目标。 该计划旨在加强操作系统技术能力&#x…

造个轮子--用Python写个语法解析器

文章目录 前言选型针对人群目标技术实现本文目标 效果实现字符指针错误类型语法解析交互 前言 目的纯粹&#xff0c;基于Python做一个简单的新的简单的编程语言。一方面是开拓视野&#xff0c;另一方面是作为毕设的临时过渡方案&#xff08;没错&#xff0c;先前提到的算法平台…

抖音短视频矩阵系统源码:SEO优化开发解析

抖音短视频矩阵系统源码是一个基于抖音短视频平台的应用程序。它允许用户上传和观看短视频&#xff0c;以及与其他用户交互。SEO优化开发解析是指对该系统进行搜索引擎优化的开发解析。 一、 在进行SEO优化开发解析时&#xff0c;可以考虑以下几点&#xff1a; 关键词优化&…

【Python数据分析】Python常用内置函数(一)

&#x1f389;欢迎来到Python专栏~Python常用内置函数&#xff08;一&#xff09; ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文…

在撰写公文时,要注意使用正确的格式和样式

在撰写公文时&#xff0c;注意使用正确的格式和样式&#xff0c;以符合公文的规范要求是非常重要的。 公文是一种正式文书&#xff0c;需要遵循一定的格式和样式要求&#xff0c;以符合公文的规范和标准。在撰写公文时&#xff0c;需要注意以下几点&#xff1a; 1.文字排版&…

day46-Quiz App(测试题计分)

50 天学习 50 个项目 - HTMLCSS and JavaScript day46-Quiz App&#xff08;测试题计分&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" conte…

【matlab】机器人工具箱快速上手-动力学仿真(代码直接复制可用)

动力学代码&#xff0c;按需修改参数 各关节力矩-关节变量的关系曲线&#xff1a; %%%%%%%%SCARA机器人仿真模型 l[0.457 0.325]; L(1) Link(d,0,a,l(1),alpha,0,standard,qlim,[-130 130]*pi/180);%连杆1 L(2)Link(d,0,a,l(2),alpha,pi,standard,qlim,[-145 145]*pi/180);%连…

代理模式--静态代理和动态代理

1.代理模式 定义&#xff1a;代理模式就是代替对象具备真实对象的功能&#xff0c;并代替真实对象完成相应的操作并且在不改变真实对象源代码的情况下扩展其功能&#xff0c;在某些情况下&#xff0c;⼀个对象不适合或者不能直接引⽤另⼀个对象&#xff0c;⽽代理对象可以在客户…

华为OD机试真题 Java 实现【最长公共后缀】【2023 B卷 100分】,等于白送

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明4、再输入5、再输出 七、机考攻略 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff…

【Golang】Golang进阶系列教程--Go 语言数组和切片的区别

文章目录 前言数组声明以及初始化函数参数 切片声明以及初始化函数参数 总结 前言 在 Go 语言中&#xff0c;数组和切片看起来很像&#xff0c;但其实它们又有很多的不同之处&#xff0c;这篇文章就来说说它们到底有哪些不同。 数组和切片是两个常用的数据结构。它们都可以用…

LBERT论文详解

论文地址&#xff1a;https://arxiv.org/abs/2105.07148 代码地址&#xff1a;https://github.com/liuwei1206/LEBERT 模型创新 LEBRT采用句子中的词语对&#xff08;论文中称为Char-Word Pair&#xff09;的特征作为输入作者设计Lexicon adapter&#xff0c;在BERT的中间某一…

Codeforces Round 839 (Div. 3)E题解

文章目录 [Permutation Game](https://codeforces.com/contest/1772/problem/E)问题建模问题分析1.分析一个玩家想要获胜的关键2.分析阻塞元素的类别3.分析阻塞元素的类别对于局面的影响代码 Permutation Game 问题建模 给定一个长度为n的排列&#xff0c;排列的每个元素都被阻…

CentOS 7安装PostgreSQL 15版本数据库

目录 一、何为PostgreSQL&#xff1f; 二、PostgreSQL安装 2.1安装依赖 2.2 执行安装 2.3 数据库初始化 2.4 配置环境变量 2.5 创建数据库 2.6 配置远程 2.7 测试远程 三、常用命令 四、用户创建和数据库权限 一、何为PostgreSQL&#xff1f; PostgreSQL是以加州大学…

DGNN Survey

Dynamic Graph Definition G ( V , E , X ) G (V, E, X) G(V,E,X) V v 1 , v 2 , . . . , v m V {v_1, v_2, ..., v_m} Vv1​,v2​,...,vm​ E e i , j E {e_{i, j}} Eei,j​ , e i , j ( v i , v j , f i , j ) e_{i,j} (v_i, v_j, f_{i,j}) ei,j​(vi​,vj​,fi,j​…

M1/M2 通过VM Fusion安装Win11 ARM,解决联网和文件传输

前言 最近新入了Macmini M2&#xff0c;但是以前的老电脑的虚拟机运行不起来了。&#x1f605;&#xff0c;实际上用过K8S的时候&#xff0c;会发现部分镜像也跑不起来&#xff0c;X86的架构和ARM实际上还是有很多隐形兼容问题。所以只能重新安装ARM Win11&#xff0c;幸好微软…

【初阶C语言】整数比大小

各位大佬的光临已是上上签 在C语言刷题过程中&#xff0c;一定遇到过很多比大小的题目&#xff0c;那么本节就专门介绍比大小的方法&#xff0c;若大佬们还有更优解&#xff0c;欢迎补充呀&#xff01; 本节讲解的方法主要有三种&#xff1a;1.条件判断 2.三目操作符 3.函数调…

JA64 1+2+3+...n

一、题目 求123...n_牛客题霸_牛客网 二、代码 1.使用静态成员变量构造函数 class SUM {private:static int _i;static int _ret;public:SUM(){_ret _ret _i;_i;}static int GetRet(){return _ret;} }; int SUM::_i1; int SUM::_ret0;class Solution { public:int Sum_So…

暴力求解--完数个数(等于本身之外的因子之和)

找出10000以内的自然数中的所有完数&#xff0c;并统计找到的完数个数。 #include<stdio.h> int main() {//找到10000以内所有的完数&#xff08;等于恰好等于它本身之外的因子之和&#xff09;&#xff0c;并统计完数个数。int n,i,s,count0;printf("找到的所有完…

jsonp 实现跨域 同时也是一个 webflux 的demo 示例

文章目录 核心原理代码html服务端 &#xff08;java 为例子&#xff09;服务端目录结构 核心原理 前端&#xff1a; 使用js 创建 script 标签&#xff0c;将请求地址&#xff0c;放到其src 中&#xff0c;并将 script 标签追加到文档流&#xff1b;后端&#xff1a;根据约定好…

Latex好看的引用(文献,url, 文内引用)

强迫症实锤了&#xff0c;完全符合本人审美&#xff01;&#xff01;&#xff01; \usepackage{hyperref} \hypersetup{ hidelinks, colorlinkstrue, linkcolorIndigo, urlcolorDeepSkyBlue4, citecolorIndigo }基本还原了 哼&#xff0c;欺负老子色彩妹那么敏感是吧&…