在微信小程序中实现virtual-list

本文介绍了微信小程序中实现虚拟列表的原理和方法,以解决长列表导致的卡顿和白屏问题。虚拟列表通过只渲染可视区域及附近的DOM元素,优化了性能。核心包括监听scroll事件,计算可视区域索引,动态更新数据渲染。文章引用了react-tiny-virtual-list等开源方案作为参考,并指出对于不可预测尺寸的瀑布流布局仍存在挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

小程序在很多场景下面会遇到长列表的交互,当一个页面渲染过多的wxml节点的时候,会造成小程序页面的卡顿和白屏。原因主要有以下几点:

  1. 列表数据量大,初始化setData和初始化渲染列表wxml耗时都比较长;
  2. 渲染的wxml节点比较多,每次setData更新视图都需要创建新的虚拟树,和旧树的diff操作耗时比较高;
  3. 渲染的wxml节点比较多,page能够容纳的wxml是有限的,占用的内存高。

微信小程序本身的scroll-view没有针对长列表做优化,官方组件recycle-view就是一个类似virtual-list的长列表组件。现在我们要剖析虚拟列表的原理,从零实现一个小程序的virtual-list。

实现原理

首先我们要了解什么是virtual-list,这是一种初始化只加载「可视区域」及其附近dom元素,并且在滚动过程中通过复用dom元素只渲染「可视区域」及其附近dom元素的滚动列表前端优化技术。相比传统的列表方式可以到达极高的初次渲染性能,并且在滚动过程中只维持超轻量的dom结构。

虚拟列表最重要的几个概念:

  • 可滚动区域:比如列表容器的高度是600,内部元素的高度之和超过了容器高度,这一块区域就可以滚动,就是「可滚动区域」;

  • 可视区域:比如列表容器的高度是600,右侧有纵向滚动条可以滚动,视觉可见的内部区域就是「可视区域」。

实现虚拟列表的核心就是监听scroll事件,通过滚动距离offset和滚动的元素的尺寸之和totalSize动态调整「可视区域」数据渲染的顶部距离和前后截取索引值,实现步骤如下:

  1. 监听scroll事件的scrollTop/scrollLeft,计算「可视区域」起始项的索引值startIndex和结束项索引值endIndex;
  2. 通过startIndex和endIndex截取长列表的「可视区域」的数据项,更新到列表中;
  3. 计算可滚动区域的高度和item的偏移量,并应用在可滚动区域和item上。

在这里插入图片描述

1.列表项的宽/高和滚动偏移量

在虚拟列表中,依赖每一个列表项的宽/高来计算「可滚动区域」,而且可能是需要自定义的,定义itemSizeGetter函数来计算列表项宽/高。

itemSizeGetter(itemSize) {
   
      return (index: number) => {
   
        if (isFunction(itemSize)) {
   
          return itemSize(index);
        }
        return isArray(itemSize) ? itemSize[index] : itemSize;
      };
    }
复制代码

滚动过程中,不会计算没有出现过的列表项的itemSize,这个时候会使用一个预估的列表项estimatedItemSize,目的就是在计算「可滚动区域」高度的时候,没有测量过的itemSize用estimatedItemSize代替。

getSizeAndPositionOfLastMeasuredItem() {
   
    return this.lastMeasuredIndex >= 0
      ? this.itemSizeAndPositionData[this.lastMeasuredIndex]
      : {
    offset: 0, size: 0 };
  }

getTotalSize(): number {
   
    const lastMeasuredSizeAndPosition = this.getSizeAndPositionOfLastMeasuredItem();
    return (
      lastMeasuredSizeAndPosition.offset +
      lastMeasuredSizeAndPosition.size +
      (this.itemCount - this.lastMeasuredIndex - 1) * this.estimatedItemSize
    );
  }
复制代码

这里看到了是直接通过缓存命中最近一个计算过的列表项的itemSize和offset,这是因为在获取每一个列表项的两个参数时候,都对其做了缓存。

 getSizeAndPositionForIndex(index: number) {
   
    if (index > this.lastMeasuredIndex) {
   
      const lastMeasuredSizeAndPosition = this.getSizeAndPositionOfLastMeasuredItem();
      let offset =
        lastMeasuredSizeAndPosition.offset + lastMeasuredSizeAndPosition.size;

      for (let i = this.lastMeasuredIndex + 1; i <= index; i++) {
   
        const size = this.itemSizeGetter(i);
        this.itemSizeAndPositionData[i] = {
   
          offset,
          size,
        };

        offset += size;
      }

      this.lastMeasuredIndex = index;
    }

    return this.itemSizeAndPositionData[index];
 }
复制代码

2.根据偏移量搜索索引值

在滚动过程中,需要通过滚动偏移量offset计算出展示在「可视区域」首项数据的索引值,一般情况下可以从0开始计算每一列表项的itemSizeÿ

<think>好的,我需要回答用户关于微信小程序系统架构设计、技术选型和架构方案的问题。首先,用户提到了两个引用,引用1是关于系统架构设计的案例,引用2是技术框架选型的分析。我需要结合这些信息,给出一个结构清晰的回答,涵盖业务架构、逻辑架构、物理架构、网络架构以及技术选型的最佳实践。 首先,系统架构设计部分,根据引用1,可以分业务、逻辑、物理、网络架构来阐述。业务架构需要明确核心功能和模块,比如证件照小程序可能有上传照片、图像处理、生成证件照等功能。逻辑架构可能包括前端、后端、云服务,前端负责交互,后端处理业务逻辑,云服务提供存储和计算。物理架构方面,使用云服务如腾讯云,部署服务器和数据库。网络架构则需要考虑CDN加速,负载均衡等优化网络请求。 然后是技术选型,引用2提到主流技术框架的比较,比如原生开发、Taro、Uni-app、WePY等。需要分析各自的优缺点,比如原生开发适合高性能需求,Taro支持多端统一开发,Uni-app生态丰富。根据团队需求和项目规模选择合适的技术栈。 架构方案的最佳实践可能需要包括分层架构设计,模块化开发,性能优化措施,安全防护,监控运维等方面。比如分层架构分为视图层、逻辑层、数据层,模块化开发提高复用性,使用CDN和缓存优化性能,接口加密和权限控制保障安全,日志监控系统维护稳定性。 最后,生成相关问题需要考虑用户可能进一步想知道的内容,比如具体某个框架的选型对比,性能优化技巧,安全措施的实施方法,或者运维监控的工具推荐等。 需要确保回答符合格式要求,使用中文,行内公式用$...$,独立公式用$$...$$,但当前问题可能不涉及数学公式,但要注意其他格式如代码块和引用标注。引用标注放在相关段落末尾,自然添加[^1][^2]。 总结结构: 1. 系统架构设计 - 业务架构 - 逻辑架构 - 物理架构 - 网络架构 2. 技术选型分析 - 原生开发 - 跨端框架 - 选型建议 3. 架构方案最佳实践 - 分层架构 - 模块化 - 性能优化 - 安全与运维 4. 相关问题 需要确保每个部分都结合引用内容,并正确标注引用来源。同时,语言要简洁明了,结构清晰,帮助用户逐步理解微信小程序的架构设计和技术选型。</think>### 微信小程序系统架构设计与技术选型 #### 一、系统架构设计 微信小程序的系统架构设计通常涵盖以下四个维度: 1. **业务架构设计** 以证件照小程序为例,核心业务模块包括: - 用户上传照片功能 - 图像处理算法(如背景替换、尺寸裁剪) - 生成标准证件照并支持下载 - 订单管理与支付集成 业务架构需明确功能边界与数据流向,例如用户请求通过API网关分发至对应服务。 2. **逻辑架构设计** 采用分层设计: - **前端逻辑层**:小程序视图层(WXML/WXSS)与逻辑层(JavaScript)分离,通过事件驱动实现交互。 - **后端服务层**:基于Node.js或Java的RESTful API,处理图像处理、用户鉴权等业务逻辑。 - **数据访问层**:通过云数据库(如腾讯云MySQL)存储用户数据和订单信息。 3. **物理架构设计** 依赖云服务资源部署: - 使用腾讯云CVM(云服务器)承载后端服务。 - 对象存储(COS)保存用户上传的原始图片与生成结果。 - 结合Serverless(云函数)处理高并发场景(如秒杀活动)。 4. **网络架构设计** - 通过CDN加速静态资源(如图片、样式文件)分发。 - 使用负载均衡(CLB)分配请求流量,避免单点故障。 - 配置SSL证书保障数据传输安全。 --- #### 二、技术选型分析 根据主流技术框架对比,选型需综合考虑开发效率、跨端能力与性能: 1. **原生开发(WXML/WXSS/JS)** - **优势**:官方支持,性能最优,适合对体验要求高的场景。 - **劣势**:多端适配需重复开发,生态工具较少[^2]。 2. **跨端框架选型** - **Taro**:基于React语法,支持编译到微信/支付宝/百度等多端,适合需要多平台覆盖的项目。 ```javascript // Taro示例:多端兼容的页面组件 import Taro from '@tarojs/taro'; export default class Index extends Taro.Component { ... } ``` - **Uni-app**:Vue语法,生态丰富,插件市场完善,但性能略低于原生。 - **WePY**:类Vue语法,专为微信定制,社区活跃度下降,适合单一平台项目[^2]。 3. **选型建议** - **轻量级工具类小程序**:优先原生开发,减少依赖。 - **跨端需求强烈**:选择Taro或Uni-app,权衡语法偏好与生态。 - **高性能计算场景**(如实时图像处理):原生开发+WebAssembly优化。 --- #### 三、架构方案最佳实践 1. **分层架构设计** - **视图层**:使用WXML+WXSS实现响应式布局,通过`<canvas>`组件处理图像渲染。 - **逻辑层**:采用Redux或MobX管理状态,避免数据冗余。 - **数据层**:结合云数据库与本地缓存(`wx.setStorageSync`),提升读取效率。 2. **模块化开发** - 将通用功能(如支付模块、图像处理SDK)封装为独立npm包。 - 使用`Jenkins`或`GitHub Actions`实现CI/CD自动化部署。 3. **性能优化** - **首屏加载**:分包加载策略,主包控制在2MB以内。 - **渲染优化**:避免频繁调用`setData`,使用`virtual-list`优化长列表- **网络请求**:合并API调用,启用HTTP/2协议。 4. **安全与运维** - **接口安全**:HTTPS传输+JWT鉴权+参数签名防篡改。 - **监控告警**:集成腾讯云「小程序云监控」,实时跟踪异常日志与性能指标。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值