!!!###!!!title=2.5 场景树更新——VisActor/VTable 社区贡献者文档!!!###!!!!!!###!!!description=---title: 2.5 场景树更新 key words: VisActor,VChart,VTable,VStrory,VMind,VGrammar,VRender,Visualization,Chart,Data,Table,Graph,Gis,LLM--- !!!###!!!

触发更新

场景树的更新会发生在什么情况下呢?一般来说是在数据改变驱动、用户交互、布局改变 三种情况下触发更新事件流程:

  • 数据驱动:当表格的属性发生变化,宽、高、图元变化的时候:分别触发updateColWidth / updateRowHeight / updateCell

  • 用户交互:用户与表格产生交互:触发resize(拖拽列宽)/ updateSortIcon(排序图标)

  • 布局改变:设备尺寸、展示模式变更触发布局上的变化,也会导致表格的更新:dealWidthMode(自适应布局)

更新流程

1. 属性修改(核心方法:

直接修改图元属性(如位置、尺寸、样式)

  • 列宽更新:通过 setAttribute 修改列容器的 width 属性。
updateColWidth(col: number, deltaX: number) {
  const columnGroup = this.getColGroup(col);
  columnGroup.setAttribute('width', newWidth); *// 直接修改列宽(触发脏标记)*
  this.updateContainer(true);                  *// 触发布局更新*
}    

  • 行高更新:调整行容器的 height 属性,同步更新垂直布局。
updateRowHeight(row: number, deltaY: number) {
  const rowGroup = this.getRowGroup(row);
  rowGroup.setAttribute('height', newHeight); *// 修改行高*
  this._updateContainerHeight(row, deltaY);    *// 联动容器高度*    


2. 布局重计算(核心方法:

基于属性变化重新计算容器坐标和尺寸,具体来说是通过 _needUpdateContainer 标记控制更新流程,这样可以确保仅当需要更新时依次执行布局计算(列宽/坐标调整)、尺寸同步(表格/冻结区)、组件状态(滚动条)等步骤,接着渲染提交(updateNextFrame),通过 stage.renderNextFrame 触发渲染引擎(渲染下一帧)

  updateContainer(async: boolean = false) {
    if (async) {
      if (!this._needUpdateContainer) {
        this._needUpdateContainer = true;
        setTimeout(() => {
          this.updateContainerSync();
        }, 0);
      }
    } else {
      this._needUpdateContainer = true;
      this.updateContainerSync();
    }
  }

 updateContainerSync() {
    if (!this._needUpdateContainer) {
      return;
    }
    this._needUpdateContainer = false;
    this.updateContainerAttrWidthAndX();
    this.updateTableSize();
    this.component.updateScrollBar();

    this.updateDomContainer();

    this.updateNextFrame();
  }
    

自适应布局:动态分配剩余空间,覆盖手动调整结果。我的解读重点是dealHeightModedealwitdhMode:

dealWidthMode() 方法负责处理表格列宽的自适应布局与自动填充逻辑:当开启 widthMode: 'adaptive' 时,首先清空历史列宽缓存,计算行表头及右侧冻结列的固定总宽度,将画布剩余空间按比例分配给非冻结列;若启用 autoFillWidth 则检测内容总宽度是否小于画布宽度,若不足则对非冻结列进行等比放大。完成列宽计算后,遍历主体区域(bodyGroup)、列头区域(colHeaderGroup)、行头区域(rowHeaderGroup)及角头区域(cornerHeaderGroup)的子列元素,累加各列实际宽度并动态设置容器总宽度,最后调整列头与主体的坐标位置,确保列头紧贴角头右侧、主体区域紧贴行头右侧,形成完整的水平布局流,最终通过容器属性更新驱动渲染引擎同步视觉表现。

dealHeightMode处理高度和处理宽度上的逻辑是高度类似、对称的。二者都符合表格自适应布局的核心思想;


3. 脏标记(VRender 内部机制)​

标记需重绘的图元,避免全量渲染。脏标记是一种性能优化技术,用于标识需要更新的数据或对象,避免全量计算或渲染,从而提升效率。在图形渲染中,它通过跟踪变化的部分,仅处理“脏”区域,而非整个场景。


4. 异步渲染提交(核心方法:
  • 统一提交入口:所有更新最终调用 stage.renderNextFrame()
updateNextFrame() {
  this.stage.renderNextFrame();
}    

本文档由以下人员修正整理

玄魂