警告 别用 ag-grid

1,888 阅读4分钟

如果你是新项目,那么不建议使用

如果你已经使用了,建议替换,如果不方便替换,那么可参考本文来进行一些调整(希望你别看吐了),

整理不易, 如果觉得对你有用 请点赞,让更多人避坑

一堆恶心的属性要配置, 才能勉强使用

 const ref = useRef<AgGridReact>(null)
  const gridRef = props.gridRef || ref
  
<AgGridReact 
              domLayout={'autoHeight'}
              suppressPropertyNamesCheck
              suppressMoveWhenRowDragging
              suppressColumnVirtualisation
              rowDragManaged={true}
              localeText={localeText}
              animateRows={true}
              className={` ${
                colorScheme === 'dark'
                  ? 'ag-theme-alpine-dark '
                  : 'ag-theme-alpine'
              } ${className}`}
              onSortChanged={onSortChanged}
              onColumnMoved={onColumnMoved}
              ref={gridRef}
              rowData={
                isPinnedTopTotalRow
                  ? postedData?.filter((item) => !item.total_row)
                  : postedData
              }
              pinnedTopRowData={
                isPinnedTopTotalRow
                  ? postedData?.filter((item) => item.total_row)
                  : undefined
              }
              columnDefs={columnDefs.map((item, index) => ({
                ...item,
                comparator: () => 0,
                // pinned 列不会显示图标
                ...(index === 0 && { rowDrag: true }),
              }))}
              defaultColDef={defaultColDef}
              onFirstDataRendered={(params) => {
                if (disableAdjustWidth) {
                  return
                }
                params.columnApi.autoSizeAllColumns(false)
           
              }}
              loadingOverlayComponent={LoadingOverlayComponent}
              noRowsOverlayComponent={() => <>empty</>}
              onGridReady={({ columnApi }) => {
                // columnApi.setColumnsVisible(hidden, false)
                // 这里设置sort的话,会触发sortChange,
                // TODO [UI] createTab之后,会导致sort icon 不显示,
                onGridReady(true)
              }}
              preventDefaultOnContextMenu
              enableCellTextSelection
              {...gridProps}
              />
              

缺点:

  • 自带的tooltip,样式丑陋,而且不会自动换行,导致内容溢出被遮挡,也不会自动调整上下方向,大概率需要自己实现, 实现时最好实现tooltip支持鼠标滑入不消失 github.com/ag-grid/ag-…, 而且显示的字段需要额外指定tooltipField?: string;,如果字段是valueGetter渲染的,那么gg吧
cellRender 无法垂直居中

解决办法:

  1. 无换行列时: .ag-cell-wrapper:{height:100%}
  2. 有换行列: 无解
    cellRenderer: (params) => {
          const row = params.data
          return (
            <Group spacing={'xs'} align="item-center">
              <Checkbox
                checked={row.status === 0}
                onChange={(event) =>
                  onStatusChange(row, event.currentTarget.checked)
                }
              />
            </Group>
          )
        },

image.png

image.png

调整行高不生效

文档用法:

.ag-theme-alpine { --ag-grid-size: 3px; --ag-list-item-height: 20px; }

按照文档的用法是不会生效的

解决办法:

.ag-theme-alpine.compact,
.ag-theme-alpine-dark.compact {
  --ag-grid-size: 3px;
  --ag-font-size: 0.6875rem;
  /* --ag-cell-horizontal-padding: 0.875rem; */
  --ag-list-item-height: 20px;
}

.ag-theme-alpine.compact .ag-layout-auto-height .ag-center-cols-clipper,
.ag-theme-alpine.compact .ag-layout-auto-height .ag-center-cols-container,
.ag-theme-alpine.compact .ag-layout-print .ag-center-cols-clipper,
.ag-theme-alpine.compact .ag-layout-print .ag-center-cols-container,
.ag-theme-alpine-dark.compact .ag-layout-auto-height .ag-center-cols-clipper,
.ag-theme-alpine-dark.compact .ag-layout-auto-height .ag-center-cols-container,
.ag-theme-alpine-dark.compact .ag-layout-print .ag-center-cols-clipper,
.ag-theme-alpine-dark.compact .ag-layout-print .ag-center-cols-container {
  min-height: 3.125rem;
}
  1. onSort 事件不给出排序的field 和sortDirection, 需要使用 GridRef 去自己捞取数据

  const onSortChanged = () => {
    const displayColumns = gridRef.current?.columnApi
      .getAllDisplayedColumns()
      .filter((item) => item.sortIndex != null)

    displayColumns?.sort((a, b) => a.sortIndex - b.sortIndex)


    const withSortColumns = columnDefs.map((column) => ({
      ...column,
      sortIndex: displayColumns?.find((it) => it.colDef.field === column.field)
        ?.sortIndex,
      sort: displayColumns?.find((it) => it.colDef.field === column.field)
        ?.sort,
    }))

    setColumnDefs(withSortColumns)
  }
  
  1. onMove 事件给出排序的field,和toIndex,然后自己整理出新的数组(合理), 但是本来按住ctrl才支持整体排序,在不按ctrl时多次快速拖拽,也会触发整体排序,而且拿到的数据是错误的
// 只处理了单列拖拽, 整体拖拽得疯狂遍历, 太浪费性能就没搞
 const onColumnMoved = useCallback(
    (event) => {
      if (isEmpty(event.column)) {
        return notifications.show({
          message: '提示:保存时,无法支持多列排序的顺序!',
          color: 'yellow',
        })
      }
      const fromIndex = columnDefs.findIndex(
        (column) => column.key === event.column!.colId
      )
      if (fromIndex === -1) return

      const sorted = arrayMoveImmutable(columnDefs, fromIndex, event.toIndex)

      setColumnDefs(sorted)
    },
    [columnDefs, setColumnDefs]
  )
  
  1. 宽度很死板(最严重), 讲道理,table元素, 使用 white-space来保证表头和内容全显示是常识,除了长内容需要特殊处理,但是 ag-grid 的css很垃圾 (看过css世界以及dom小测,这点评鉴力还是有的) , 以至于:

列少不会自动撑满宽度,导致右侧有空格; 列多时,表头会显示省略号,需要自己使用 columnApi.autoSizeAllColumns(false)调整一下, 但是列少时,只想要撑满,你应该使用sizeToFit,因此, 需要人工判断该调用哪个api, 另外使用api调整好了宽度,当排序图标出现时,又会使表头出现省略号

antd正确: 的宽度由内容撑开

image.png

ag-grid 错误: 写死宽度

image.png

宽度 demo:

根据列的数量来判断也不对,总之 貌似是个无解的题
类比antd,做的就很好, 列少时,会自动撑满整行,列多时表头不会显示省略号,没有任何负担

image.png

另外, 自动调整宽度 + 左侧固定列一起使用时, 会导致可滚动列的宽度很小, 这可能不算ag-grid的bug,但是真的巨特么难用

image.png

  1. 没有任何好看的主题, 需要自己去构建,社区也没有

showLoadingOverlay 不生效

issue: github.com/ag-grid/ag-…

解决办法1(可能解决): noRowsOverlayComponent 做成动态的

useEffect(() => {
    loading && gridReady
      ? gridRef.current?.api?.showLoadingOverlay()
      : gridRef.current?.api?.hideOverlay()
})
    
    loadingOverlayComponent={()=> <span>loading</span>}
    //  noRowsOverlayComponent={()=> <span>empty</span>} 
    noRowsOverlayComponent={() => (loading ? <span>loading</span> : <span>empty</span>)}

useEffect 里执行ref, 这是react文档推荐的 Best practices for refs的, 我们的用法没错,但是依然可能不显示loading

解决办法2: 去掉useEffect, 直接判断,仍然可能失效 哈哈

```jsx
loading && gridReady
  ? gridRef.current?.api?.showLoadingOverlay()
  : gridRef.current?.api?.hideOverlay()
```

解决办法3: 自己用一个div模拟loading来包装ag-grid,然后禁用他自带的loading, 貌似也不好用,所以放弃了(我尝试过,忘记了)

表头没有水平居中的方法

github.com/ag-grid/ag-…

而在 antd 里 `align:'center'`