现在的网站用什么程序做,齐河县工程建设监理有限公司网站,进入 网站cms,济南网站建设选搜点网络前言
由于svelte solid 两大无虚拟DOM框架#xff0c;由于其性能好#xff0c;在前端越来越有影响力。
因此本次想要验证#xff0c;这三个框架关于实现表格虚拟滚动的性能。
比较版本
vue3.4.21svelte4.2.12solid-js1.8.15
比较代码
这里使用了我的 stk-table-vue(np…前言
由于svelte solid 两大无虚拟DOM框架由于其性能好在前端越来越有影响力。
因此本次想要验证这三个框架关于实现表格虚拟滚动的性能。
比较版本
vue3.4.21svelte4.2.12solid-js1.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因为headlesstrue无头时需要上下各预渲染一行。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
templatediv classstk-table reftableContainer scrollonTableScrolltable classstk-table-maintheadtrth v-forcol in columns :keycol.dataIndex :data-col-keycol.dataIndex{{ col.title || -- }}/th/tr/theadtbodytr :style{ height: ${virtualScroll.offsetTop}px }/trtr v-forrow in virtual_dataSourcePart :keyrow.idtd v-forcol in columns :keycol.dataIndex{{ row[col.dataIndex] || -- }}/td/trtr :style{ height: ${virtual_offsetBottom}px }/tr/tbody/table/div
/templateStkTable.svelte
scriptimport { 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因为headlesstrue无头时需要上下各预渲染一行。$: 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);}}
/scriptdiv classstk-table bind:this{tableContainer} {style} on:scroll{onTableScroll}table classstk-table-maintheadtr{#each columns as col (col.dataIndex)}th data-col-key{col.dataIndex}{col.title || --}/th{/each}/tr/theadtbodytr styleheight: {${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 styleheight: {${virtual_offsetBottom}px}/tr/tbody/table
/divStkTable.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因为headlesstrue无头时需要上下各预渲染一行。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 classstk-table ref{tableContainer} style{props.style} onScroll{onTableScroll}table classstk-table-maintheadtrFor each{props.columns}{(col) th data-col-key{col.dataIndex}{col.title || --}/th}/For/tr/theadtbodytr style{{ height: ${virtualScroll().offsetTop}px }}/trFor each{virtual_dataSourcePart()}{(row) trFor each{props.columns}{(col) td{row[col.dataIndex] || --}/td}/For/tr}/Fortr 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在虚拟滚动情况下未能观察到明显优势。