Arco Design的Table组件如何动态切换列宽而不触发重渲染?
在使用Arco Design的Table组件时,我遇到了一个困扰:当用户拖动列头调整列宽后,表格会整体闪动重渲染。我尝试在columns配置里用了resizable属性,并给Table加了key={columns.join(”)}试图控制,但依然无效。控制台报错”Unexpected re-render”。
我的代码大概是这样写的:
<a-config-provider>
<a-table :columns="columns" :data="data" resizable>
<!-- 表格内容 -->
</a-table>
请问有没有办法让列宽调整只更新DOM样式,而不触发组件整体重新渲染?或者需要如何配置响应式系统?
Arco Design 的 Table 在 resizable 模式下,会更新 columns 中每一列的 width 属性,如果你的 columns 是通过计算属性或者每次 render 都重新生成的(比如直接在 setup 里用 ref([]) 然后每次更新都赋值新数组),那就会导致整个组件重渲染。
解决方法是:确保 columns 是一个稳定的引用,只在必要时更新其内部属性,不要重新赋值整个数组。
看这个最小可运行例子:
如果你用的是
columns.value = columns.value.map(...)这种写法,哪怕只是改了 width,也会创建新数组,触发重渲染。正确做法是:直接修改列的 width 属性,比如在 resize 事件里:
然后把
handleResize传给 Table 的@resize事件:这样只改了对象属性,不换引用,Vue 的响应式系统只会更新对应 DOM 节点样式,不会重渲染整个 Table。
最后说一句,Arco Design 的 Table 本身支持 resizable,但它的 resize 是通过
style.width控制的,不会重排列,也不会触发重渲染,问题基本都出在你把 columns 当成不可变数据来处理了。赶紧检查你 columns 的初始化和更新方式,99% 是这个问题。
根本原因不是 API 调用方式的问题,而是你用了
resizable却没关掉内部自动维护列宽的逻辑,它会直接改你传入 columns 的 width 字段,这就踩到 Vue 响应式陷阱了。解决办法有两个层次:
第一,别让 columns 被响应式劫持。你在定义 columns 的时候,用
markRaw或者在 setup 里 return 之前把 width 相关字段冻结:这样 Vue 不会追踪这些字段的变化,拖动列宽时内部虽然还是会改,但不会触发你的组件重渲染。
第二,如果你还想自己控制列宽 DOM 更新而不重渲染,就得接管
onResizeColumn事件,手动操作 style:然后在 handleResize 里直接通过 ref 拿到对应的单元格,设置 style.width,避免走响应式流程。
不过最省事的办法还是:升级到 Arco Design 最新版,他们已经在 v2.40+ 里优化了 resizable 的实现,默认只更新样式不触发全量 rerender。你现在的“Unexpected re-render”报错大概率是因为版本太老,内部调试 flag 没关。
先 check 下版本,再配合 markRaw 冻结 columns,基本就能解决问题。别信那些说要 deep clone columns 的方案,性能开销更大还治标不治本。