Arco Design的Table组件如何动态切换列宽而不触发重渲染?

宇文丽苹 阅读 122

在使用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样式,而不触发组件整体重新渲染?或者需要如何配置响应式系统?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
公孙玉浩
代码给你,核心问题是 columns 是响应式引用,每次调整列宽后如果重新生成了 columns 数组,就会触发整个 Table 重渲染。

Arco Design 的 Table 在 resizable 模式下,会更新 columns 中每一列的 width 属性,如果你的 columns 是通过计算属性或者每次 render 都重新生成的(比如直接在 setup 里用 ref([]) 然后每次更新都赋值新数组),那就会导致整个组件重渲染。

解决方法是:确保 columns 是一个稳定的引用,只在必要时更新其内部属性,不要重新赋值整个数组。

看这个最小可运行例子:

<template>
<a-config-provider>
<a-table :columns="columns" :data="data" resizable />
</a-config-provider>
</template>

<script setup>
import { ref, reactive } from 'vue'

const data = ref([
{ id: 1, name: '张三', age: 28, address: '杭州' },
{ id: 2, name: '李四', age: 32, address: '上海' }
])

// ✅ 正确:columns 是 ref 包装的数组,且不重新赋值整个数组
const columns = ref([
{ title: '姓名', dataIndex: 'name', width: 120 },
{ title: '年龄', dataIndex: 'age', width: 80 },
{ title: '地址', dataIndex: 'address', width: 200 }
])

// ❌ 错误:不要在 resize 事件里重新赋值整个 columns 数组
// 比如 columns.value = [...columns.value, ...] 或 columns.value = cloneDeep(...)
// 这种写法会改变引用,导致 Table 觉得列配置变了,重渲染

// 如果你用了 computed 或者其他方式动态生成 columns,也要确保返回的是同一个引用(不推荐)
</script>


如果你用的是 columns.value = columns.value.map(...) 这种写法,哪怕只是改了 width,也会创建新数组,触发重渲染。

正确做法是:直接修改列的 width 属性,比如在 resize 事件里:

const handleResize = ({ column, size }) => {
const col = columns.value.find(c => c.dataIndex === column.dataIndex)
if (col) {
col.width = size.width
}
}


然后把 handleResize 传给 Table 的 @resize 事件:

<a-table :columns="columns" :data="data" resizable @resize="handleResize" />


这样只改了对象属性,不换引用,Vue 的响应式系统只会更新对应 DOM 节点样式,不会重渲染整个 Table。

最后说一句,Arco Design 的 Table 本身支持 resizable,但它的 resize 是通过 style.width 控制的,不会重排列,也不会触发重渲染,问题基本都出在你把 columns 当成不可变数据来处理了。

赶紧检查你 columns 的初始化和更新方式,99% 是这个问题。
点赞 2
2026-02-25 17:09
百里欢欢
你这个问题其实是 Arco Design 的 Table 在处理列宽拖动时,内部状态更新触发了 Vue 的响应式系统,导致整个表格组件重新渲染。加 key 来控制也没用,因为 columns 本身是响应式引用,只要它的某个属性变了(比如 width),就会触发依赖收集的更新。

根本原因不是 API 调用方式的问题,而是你用了 resizable 却没关掉内部自动维护列宽的逻辑,它会直接改你传入 columns 的 width 字段,这就踩到 Vue 响应式陷阱了。

解决办法有两个层次:

第一,别让 columns 被响应式劫持。你在定义 columns 的时候,用 markRaw 或者在 setup 里 return 之前把 width 相关字段冻结:

import { markRaw } from 'vue'

const columns = markRaw([
{ title: '姓名', dataIndex: 'name', width: 100 },
{ title: '年龄', dataIndex: 'age', width: 100 }
])


这样 Vue 不会追踪这些字段的变化,拖动列宽时内部虽然还是会改,但不会触发你的组件重渲染。

第二,如果你还想自己控制列宽 DOM 更新而不重渲染,就得接管 onResizeColumn 事件,手动操作 style:

<a-table 
:columns="columns"
:data="data"
@resize-column="handleResize"
resizable
></a-table>


然后在 handleResize 里直接通过 ref 拿到对应的单元格,设置 style.width,避免走响应式流程。

不过最省事的办法还是:升级到 Arco Design 最新版,他们已经在 v2.40+ 里优化了 resizable 的实现,默认只更新样式不触发全量 rerender。你现在的“Unexpected re-render”报错大概率是因为版本太老,内部调试 flag 没关。

先 check 下版本,再配合 markRaw 冻结 columns,基本就能解决问题。别信那些说要 deep clone columns 的方案,性能开销更大还治标不治本。
点赞 12
2026-02-09 08:21