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

vue svelte solid 虚拟滚动性能对比

前言

由于svelte solid 两大无虚拟DOM框架,由于其性能好,在前端越来越有影响力。

因此本次想要验证,这三个框架关于实现表格虚拟滚动的性能。

比较版本

  • vue@3.4.21
  • svelte@4.2.12
  • solid-js@1.8.15

比较代码

这里使用了我的 stk-table-vue(npm) 中实现虚拟滚动主要代码。

StkTable.vue

<script setup>
import { onMounted, ref, computed } from 'vue';
const props = defineProps({virtual: {type: Boolean,default: true},columns: {type: Array},dataSource: {type: Array}
})
const tableContainer = ref();
const virtualScroll = ref({containerHeight: 0,startIndex: 0, // 数组开始位置rowHeight: 28,offsetTop: 0, // 表格定位上边距scrollTop: 0, // 纵向滚动条位置,用于判断是横向滚动还是纵向
});const dataSourceCopy = computed(() => [...props.dataSource]);const virtual_pageSize = computed(() => Math.ceil(virtualScroll.value.containerHeight / virtualScroll.value.rowHeight) + 1); // 这里最终+1,因为headless=true无头时,需要上下各预渲染一行。const virtual_on = computed(() => props.virtual && dataSourceCopy.value.length > virtual_pageSize.value * 2)
const virtual_dataSourcePart = computed(() => virtual_on.value? dataSourceCopy.value.slice(virtualScroll.value.startIndex, virtualScroll.value.startIndex + virtual_pageSize.value): dataSourceCopy.value)
const virtual_offsetBottom = computed(() => virtual_on.value ? (dataSourceCopy.value.length - virtualScroll.value.startIndex - virtual_dataSourcePart.value.length) * virtualScroll.value.rowHeight : 0)onMounted(() => {initVirtualScroll();
})/*** 初始化虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/
function initVirtualScroll(height) {initVirtualScrollY(height);// this.initVirtualScrollX();
}
/*** 初始化Y虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/
function initVirtualScrollY(height) {if (virtual_on.value) {virtualScroll.value.containerHeight = typeof height === 'number' ? height : tableContainer.value?.offsetHeight;updateVirtualScrollY(tableContainer.value?.scrollTop);}
}
/** 通过滚动条位置,计算虚拟滚动的参数 */
function updateVirtualScrollY(sTop = 0) {const { rowHeight } = virtualScroll.value;const startIndex = Math.floor(sTop / rowHeight);Object.assign(virtualScroll.value, {startIndex,offsetTop: startIndex * rowHeight, // startIndex之前的高度});
}function onTableScroll(e) {if (!e?.target) return;// 此处可优化,因为访问e.target.scrollXX消耗性能const { scrollTop, scrollLeft } = e.target;// 纵向滚动有变化if (scrollTop !== virtualScroll.value.scrollTop) virtualScroll.value.scrollTop = scrollTop;if (virtual_on.value) {updateVirtualScrollY(scrollTop);}
}
</script>
<template><div class="stk-table" ref="tableContainer" @scroll="onTableScroll"><table class="stk-table-main"><thead><tr><th v-for="col in columns" :key="col.dataIndex" :data-col-key="col.dataIndex">{{ col.title || '--' }}</th></tr></thead><tbody><tr :style="{ height: `${virtualScroll.offsetTop}px` }"></tr><tr v-for="row in virtual_dataSourcePart" :key="row.id"><td v-for="col in columns" :key="col.dataIndex">{{ row[col.dataIndex] || '--' }}</td></tr><tr :style="{ height: `${virtual_offsetBottom}px` }"></tr></tbody></table></div>
</template>

StkTable.svelte

<script>import { onMount } from 'svelte';import '../stk-table/stk-table.less';export let style = '';export let virtual = true;let tableContainer;let virtualScroll = {containerHeight: 0,startIndex: 0, // 数组开始位置rowHeight: 28,offsetTop: 0, // 表格定位上边距scrollTop: 0, // 纵向滚动条位置,用于判断是横向滚动还是纵向};export let columns = [{ dataIndex: 'id', title: 'ID' },{ dataIndex: 'name', title: 'Name' },];export let dataSource = [];$: dataSourceCopy = [...dataSource];/** 数据量大于2页才开始虚拟滚动*//** 虚拟滚动展示的行数 */$: virtual_pageSize = Math.ceil(virtualScroll.containerHeight / virtualScroll.rowHeight) + 1; // 这里最终+1,因为headless=true无头时,需要上下各预渲染一行。$: virtual_on = virtual && dataSourceCopy.length > virtual_pageSize * 2;/** 虚拟滚动展示的行 */$: virtual_dataSourcePart = virtual_on? dataSourceCopy.slice(virtualScroll.startIndex, virtualScroll.startIndex + virtual_pageSize): dataSourceCopy;/** 虚拟表格定位下边距*/$: virtual_offsetBottom = virtual_on ?(dataSourceCopy.length - virtualScroll.startIndex - virtual_dataSourcePart.length) * virtualScroll.rowHeight : 0;onMount(() => {initVirtualScroll();});/*** 初始化虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/function initVirtualScroll(height) {initVirtualScrollY(height);// this.initVirtualScrollX();}/*** 初始化Y虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/function initVirtualScrollY(height) {if(virtual_on){virtualScroll.containerHeight = typeof height === 'number' ? height : tableContainer?.offsetHeight;virtualScroll = virtualScroll;updateVirtualScrollY(tableContainer?.scrollTop);}}/** 通过滚动条位置,计算虚拟滚动的参数 */function updateVirtualScrollY(sTop = 0) {const { rowHeight } = virtualScroll;const startIndex = Math.floor(sTop / rowHeight);Object.assign(virtualScroll, {startIndex,offsetTop: startIndex * rowHeight, // startIndex之前的高度});}function onTableScroll(e) {if (!e?.target) return;// 此处可优化,因为访问e.target.scrollXX消耗性能const { scrollTop, scrollLeft } = e.target;// 纵向滚动有变化if (scrollTop !== virtualScroll.scrollTop) virtualScroll.scrollTop = scrollTop;if (virtual_on) {updateVirtualScrollY(scrollTop);}}
</script><div class="stk-table" bind:this={tableContainer} {style} on:scroll={onTableScroll}><table class="stk-table-main"><thead><tr>{#each columns as col (col.dataIndex)}<th data-col-key={col.dataIndex}>{col.title || '--'}</th>{/each}</tr></thead><tbody><tr style="height: {`${virtualScroll.offsetTop}px`}"></tr>{#each virtual_dataSourcePart as row (row.id)}<tr>{#each columns as col (col.dataIndex)}<td>{row[col.dataIndex] || '--'}</td>{/each}</tr>{/each}<tr style="height: {`${virtual_offsetBottom}px`}"></tr></tbody></table>
</div>

StkTable.jsx (solid-js)

import { For, createSignal, onMount } from "solid-js";
import '../stk-table/stk-table.less';export function StkTable(props) {let tableContainer;const [virtualScroll, setVirtualScroll] = createSignal({containerHeight: 0,startIndex: 0, // 数组开始位置rowHeight: 28,offsetTop: 0, // 表格定位上边距scrollTop: 0, // 纵向滚动条位置,用于判断是横向滚动还是纵向});const [dataSourceCopy, setDataSourceCopy] = createSignal([]);const virtual_pageSize = () => {const vs = virtualScroll();return Math.ceil(vs.containerHeight / vs.rowHeight) + 1}; // 这里最终+1,因为headless=true无头时,需要上下各预渲染一行。const virtual_on = () => props.virtual && dataSourceCopy().length > virtual_pageSize() * 2;/** 虚拟滚动展示的行 */const virtual_dataSourcePart = () => {const vs = virtualScroll();const pageSize = virtual_pageSize();console.log(vs, pageSize)return virtual_on()? dataSourceCopy().slice(vs.startIndex, vs.startIndex + pageSize): dataSourceCopy()};/** 虚拟表格定位下边距*/const virtual_offsetBottom = () => virtual_on() ? (dataSourceCopy().length - virtualScroll().startIndex - virtual_dataSourcePart().length) * virtualScroll().rowHeight : 0;onMount(() => {setDataSourceCopy([...props.dataSource]);initVirtualScroll();});/*** 初始化虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/function initVirtualScroll(height) {initVirtualScrollY(height);// this.initVirtualScrollX();}/*** 初始化Y虚拟滚动参数* @param {number} [height] 虚拟滚动的高度*/function initVirtualScrollY(height) {if (virtual_on()) {const vs = virtualScroll()vs.containerHeight = typeof height === 'number' ? height : tableContainer?.offsetHeight;setVirtualScroll(vs);updateVirtualScrollY(tableContainer?.scrollTop);}}/** 通过滚动条位置,计算虚拟滚动的参数 */function updateVirtualScrollY(sTop = 0) {let vs = virtualScroll();const startIndex = Math.floor(sTop / vs.rowHeight);Object.assign(vs, {startIndex,offsetTop: startIndex * vs.rowHeight, // startIndex之前的高度});setVirtualScroll({...vs});// 必须扩展运算,否则不触发更新}function onTableScroll(e) {if (!e?.target) return;// 此处可优化,因为访问e.target.scrollXX消耗性能const { scrollTop, scrollLeft } = e.target;const vs = virtualScroll()// 纵向滚动有变化if (scrollTop !== vs.scrollTop) {vs.scrollTop = scrollTop;setVirtualScroll(vs);}if (virtual_on()) {updateVirtualScrollY(scrollTop);}}return <div class="stk-table" ref={tableContainer} style={props.style} onScroll={onTableScroll}><table class="stk-table-main"><thead><tr><For each={props.columns}>{(col) =><th data-col-key={col.dataIndex}>{col.title || '--'}</th>}</For></tr></thead><tbody><tr style={{ height: `${virtualScroll().offsetTop}px` }}></tr><For each={virtual_dataSourcePart()}>{(row) =><tr><For each={props.columns}>{(col) => <td>{row[col.dataIndex] || '--'}</td>}</For></tr>}</For><tr style={{ height: `${virtual_offsetBottom()}px` }}></tr></tbody></table></div>
}

style.less

src/StkTable/style.less · JA+/stk-table-vue

性能比较

比较虚拟滚动性能。

通过长按键盘↓键滚动,且将电脑cpu速度调至减速6x

观察浏览器开发者面板performance标签下的任务耗时。

vue任务

svelte任务

solid任务

结论

观察solid任务的超时情况(红色部分),大体比vue与svelte要少。

solid与svelte 相较vue在虚拟滚动情况下,未能观察到明显优势。

相关文章:

vue svelte solid 虚拟滚动性能对比

前言 由于svelte solid 两大无虚拟DOM框架&#xff0c;由于其性能好&#xff0c;在前端越来越有影响力。 因此本次想要验证&#xff0c;这三个框架关于实现表格虚拟滚动的性能。 比较版本 vue3.4.21svelte4.2.12solid-js1.8.15 比较代码 这里使用了我的 stk-table-vue(np…...

IDEA中新增文件,弹出框提示是否添加到Git点错了,怎么重新设置?

打开一个配置了Git的项目&#xff0c;新增一个文件&#xff0c;会弹出下面这个框。提示是否将新增的文件交给Git管理。 一般来说&#xff0c;会选择ADD&#xff0c;并勾选Dont ask agin&#xff0c;添加并不再询问。如果不小心点错了&#xff0c;可在IDEA中重新设置&#xff08…...

LV15 day5 字符设备驱动读写操作实现

一、读操作实现 ssize_t xxx_read(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos); 完成功能&#xff1a;读取设备产生的数据 参数&#xff1a; filp&#xff1a;指向open产生的struct file类型的对象&#xff0c;表示本次read对应的那次open pbuf&#…...

Uninty 鼠标点击(摄像机发出射线-检测位置)

平面来触发碰撞&#xff0c;胶囊用红色材质方便观察。 脚本挂载到胶囊上方便操作。 目前实现的功能&#xff0c;鼠标左键点击&#xff0c;胶囊就移动到那个位置上。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c6 : MonoBe…...

描述下Vue自定义指令

描述下Vue自定义指令 &#xff08;1&#xff09;自定义指令基本内容&#xff08;2&#xff09;使用场景&#xff08;3&#xff09;使用案例 在 Vue2.0 中&#xff0c;代码复用和抽象的主要形式是组件。然而&#xff0c;有的情况下&#xff0c;你仍然需要对普通 DOM 元素进行底层…...

2024.3.7

作业&#xff1a; 1、OSI的七层网络模型有哪些&#xff0c;每一层有什么作用&#xff1f; &#xff08;1&#xff09;应用层 负责处理不同应用程序之间的通信&#xff0c;需要满足提供的协议&#xff0c;确保数据发送方和接收方的正确 &#xff08;2&#xff09;表示层…...

this.$watch 侦听器 和 停止侦听器

使用组件实例的$watch()方法来命令式地创建一个侦听器&#xff1b; 它还允许你提前停止该侦听器 语法&#xff1a;this.$watch(data, method, object) 1. data&#xff1a;侦听的数据源&#xff0c;类型为String 2. method&#xff1a;回调函数&#x…...

P1030 [NOIP2001 普及组] 求先序排列题解

题目 给出一棵二叉树的中序与后序排列。求出它的先序排列。&#xff08;约定树结点用不同的大写字母表示&#xff0c;且二叉树的节点个数≤8&#xff09;。 输入输出格式 输入格式 共两行&#xff0c;均为大写字母组成的字符串&#xff0c;表示一棵二叉树的中序与后序排列。…...

【分布式】NCCL Split Tree kernel内实现情况 - 06

相关系列 【分布式】NCCL部署与测试 - 01 【分布式】入门级NCCL多机并行实践 - 02 【分布式】小白看Ring算法 - 03 【分布式】大模型分布式训练入门与实践 - 04 目录 相关系列概述1.1 Tree1.2 double binary tree初始化和拓扑2.1 Tree的初始化与差异2.2 ncclGetBtreeKernel内部…...

C语言深入学习 --- 4.自定义类型(结构体+枚举+联合)

第四章 自定义类型&#xff1a;结构体&#xff0c;枚举&#xff0c;联合 结构体 结构体类型的声明 结构的自引用 结构体变量的定义和初始化 结构体的内存对齐 结构体实现位段&#xff08;位段的填充 和 可移植性&#xff09; 枚举 枚举类型的定义 枚举的优点 枚举的使…...

AI自然语言中默认上下文长度4K 几K是什么意思?

环境&#xff1a; 4K 问题描述&#xff1a; AI自然语言中默认上下文长度4K 几K是什么意思&#xff1f; 解决方案&#xff1a; 在自然语言处理中&#xff0c;“k” 表示 “千”&#xff0c;是一种简写方式。当我们说 “4k” 时&#xff0c;实际上指的是 “4,000”。在上下文…...

vSphere 8考试认证题库 2024最新(VCP 8.0版本)

VMware VCP-DCV&#xff08;2V0-21.23&#xff09;认证考试题库&#xff0c;已全部更新&#xff0c;答案已经完成校对&#xff0c;完整题库请扫描上方二维码访问。正常考可以考到450分以上&#xff08;满分500分&#xff0c;300分通过&#xff09; An administrator is tasked …...

系统学习Python——装饰器:“私有“和“公有“属性案例-[装饰器参数、状态保持和外层作用域]

分类目录&#xff1a;《系统学习Python》总目录 文章《系统学习Python——装饰器&#xff1a;“私有“和“公有“属性案例-[实现私有属性]》中使用的类装饰器接受任意多个参数来命名私有属性。然而真正发生的情况是&#xff0c;参数传递给了Private函数&#xff0c;然后Private…...

星辰天合参与编制 国内首个可兼顾 AI 大模型训练的高性能计算存储标准正式发布

近日&#xff0c;在中国电子工业标准化技术协会高标委的支持和指导下&#xff0c;XSKY星辰天合作为核心成员参与编制的《高性能计算分布式存储系统技术要求》团体标准&#xff0c;在中国电子工业标准化技术协会网站正式发布。 该团体标准强调了分布式存储系统对包括传统高性能计…...

算法训练day38动态规划基础Leetcode509斐波纳切数70爬楼梯746使用最小花费爬楼梯

什么是动态规划 对于动态规划问题&#xff0c;我将拆解为如下五步曲&#xff0c;这五步都搞清楚了&#xff0c;才能说把动态规划真的掌握了&#xff01; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组&a…...

Leetcode 206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1] 示例 3&#xff1a; 输…...

电子科技大学课程《计算机网络系统》(持续更新)

前言 本校的课程课时有所缩减&#xff0c;因此可能出现与你学习的课程有所减少的情况&#xff0c;因此对其他学校的同学更多的作为参考作用。本文章适合学生的期中期末考试&#xff0c;以及想要考研电子科技大学的同学&#xff0c;电子科技大学同学请先看附言。 第一章 计算…...

HBase介绍、特点、应用场景、生态圈

目录: 一、HBase简介 二、NoSQL和关系型数据库对比 三、HBase特点 四、应用场景 五、HBase生态圈技术 一、HBase简介 HBase是一个领先的NoSQL数据库 是一个面向列存储的NoSQL数据库 是一个分布式Hash Map&#xff0c;底层数据是Key-Value格式 基于Coogle Big Table论文 使用HD…...

蓝桥杯错误记录

今天在做 小蜜蜂的综合案例的时候&#xff0c;数码管显示&#xff0c;有重影。 #include <STC15F2K60S2.H> unsigned char num; unsigned char code Duan[22]{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x80, 0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0XC1,0X8C,0…...

Spring-静态代理VS动态代理/实现代理ProxyFactory

文章目录 静态代理VS动态代理Spring实现代理ProxyFactory 工作中遇到问题整理动态代理异常com.sun.proxy.$Proxy0 cannot be cast to 静态代理VS动态代理 静态代理VS动态代理 参考URL: https://blog.csdn.net/qq_25881443/article/details/103245938 【java项目实战】代理模式…...

单片机精进之路-9ds18b20温度传感器

ds18b20复位时序图&#xff0c;先将b20的数据引脚拉低至少480us&#xff0c;然后再将数据引脚拉高15-60us&#xff0c;再去将测传感器的数据引脚是不是变低电平并保持60-240us&#xff0c;如果是&#xff0c;则说明检测到温度传感器&#xff0c;并正常工作。需要在240us后才能检…...

支部管理系统微信小程序(管理端+用户端)flask+vue+mysql+微信小程序

系统架构如图所示 高校D支部管理系统 由web端和微信小程序端组成&#xff0c;由web端负责管理&#xff0c;能够收缴费用、发布信息、发布问卷、发布通知等功能 部分功能页面如图所示 微信小程序端 包含所有源码和远程部署&#xff0c;可作为毕设课设...

4、Linux-常用命令(二)

目录 一、搜索命令 1、命令搜索命令 2、文件搜索命令find。格式&#xff1a;find [搜索范围] [搜索条件]。 3、字符串搜索命令grep 二、帮助命令 1、man【详细的帮助】 2、--help【简要的帮助】 三、压缩与解压命令 1、.zip格式 2、.gz格式 3、打包 四、关机和重启命…...

golang实现openssl自签名双向认证

第一步&#xff1a;生成CA、服务端、客户端证书 1. 生成CA根证书 生成CA证书私钥 openssl genrsa -out ca.key 4096创建ca.conf 文件 [ req ] default_bits 4096 distinguished_name req_distinguished_name[ req_distinguished_name ] countryName …...

【学习】torchvision.datasets.ImageFolder()

在分类任务中&#xff0c;数据集文件存储往往是如下形式&#xff1a; - train- class1- image1.jpg- image2.jpg...- class2- image1.jpg- image2.jpg......此时&#xff0c;我们想要获取图片和标签&#xff0c;标签即为文件名&#xff08;class1、class2…&#xff09; 可以使…...

pyinstaller打包的exe运行报错 No module named path

描述 用python开发了一个opc client应用&#xff0c;调试没有问题后&#xff0c;使用pyinstaller打包成exe&#xff0c;测试exe运行也没有问题&#xff0c;正常使用。 在某次重装win10系统后&#xff0c;在此运行exe就开始报错了&#xff0c;详细内容如下&#xff1a; ------…...

Vue3中Vuex状态管理库学习笔记

1.什么是状态管理 在开发中&#xff0c;我们会的应用程序需要处理各种各样的数据&#xff0c;这些数据需要保存在我们应用程序的某个位置&#xff0c;对于这些数据的管理我们就称之为状态管理。 在之前我们如何管理自己的状态呢&#xff1f; 在Vue开发中&#xff0c;我们使用…...

React富文本编辑器开发(二)

我们接着上一节的示例内容&#xff0c;现在有如下需求&#xff0c;我们希望当我们按下某个按键时编辑器有所反应。这就需要我们对编辑器添加事件功能onKeyDown, 我们给 Editor添加事件&#xff1a; SDocor.jsx import { useState } from react; import { createEditor } from…...

nginx代理minio客户端

错误方式 在点击桶名查看文件时, 会一直处于loading加载中 worker_processes 1; #设置 Nginx 启动的工作进程数为 1。events {worker_connections 1024; ##设置每个工作进程的最大并发连接数为 1024。 }http {include mime.types; #该文件定义了文件扩展名和 MIME 类型…...

将ppt里的视频导出来

将ppt的后缀从pptx改为zip 找到【media】里面有存放图片和音频以及视频&#xff0c;看文件名后缀可以找到&#xff0c;mp4的即为视频&#xff0c;直接复制粘贴到桌面即可。 关闭压缩软件把ppt后缀改回&#xff0c;不影响ppt正常使用。...