首页 > 解决方案 > 如何在 ag-grid 顶部添加水平滚动条

问题描述

我设置了一个 ag-grid,其中包含一系列用于单元格渲染的组件。当我的数据集加载垂直滚动时效果很好,但水平滚动并不明显,除非使用触控板或启用水平滚动的鼠标。

我希望能够在网格顶部添加一个滚动条以及在底部自动生成一个滚动条吗?

有没有人遇到过这种情况,想出解决办法吗?

提前致谢

标签: ag-grid

解决方案


这个问题很老,但我在同样的问题上苦苦挣扎并想出了一些可行的方法。

理念

我的解决方案背后的主要思想是......

  • 网格准备好时克隆 AgGrid 滚动条
  • 在网格顶部插入克隆的滚动条
  • 在两个滚动条上添加事件侦听器以保持滚动位置同步
  • 使用MutationObserver观察style原始 AgGrid 滚动条元素(和子元素)的属性变化,以保持克隆滚动条的大小同步

⚡ 代码

以下代码适用于 Angular,但概念与 Vanilla JS、React 或 Vue 相同。

首先,获取gridReady事件挂钩:

<ag-grid-angular
  ...
  (gridReady)="onGridReady()">
</ag-grid-angular>

在与事件关联的函数中,使用以下代码克隆 AgGrid 滚动条并保持滚动条同步:

// hold the `MutationObserver` to be disconnected when component is destroyed
private mutationObserver: MutationObserver;

onGridReady() {
  // css class selectors
  const headerSelector = '.ag-header';
  const scrollSelector = '.ag-body-horizontal-scroll';
  const scrollViewportSelector = '.ag-body-horizontal-scroll-viewport';
  const scrollContainerSelector = '.ag-body-horizontal-scroll-container';

  // get scrollbar elements
  const scrollElement = document.querySelector(scrollSelector);
  const scrollViewportElement = document.querySelector(scrollViewportSelector);
  const scrollContainerElement = document.querySelector(scrollContainerSelector);

  // create scrollbar clones
  const cloneElement = scrollElement.cloneNode(true) as Element;
  const cloneViewportElement = cloneElement.querySelector(scrollViewportSelector);
  const cloneContainerElement = cloneElement.querySelector(scrollContainerSelector);

  // insert scrollbar clone
  const headerElement = document.querySelector(headerSelector);
  headerElement.insertAdjacentElement('afterend', cloneElement);

  // add event listeners to keep scroll position synchronized
  scrollViewportElement.addEventListener('scroll', () => cloneViewportElement.scrollTo({ left: scrollViewportElement.scrollLeft }));
  cloneViewportElement.addEventListener('scroll', () => scrollViewportElement.scrollTo({ left: cloneViewportElement.scrollLeft }));

  // create a mutation observer to keep scroll size synchronized
  this.mutationObserver = new MutationObserver(mutationList => {
    for (const mutation of mutationList) {
      switch (mutation.target) {
        case scrollElement:
          cloneElement.setAttribute('style', scrollElement.getAttribute('style'));
          break;
        case scrollViewportElement:
          cloneViewportElement.setAttribute('style', scrollViewportElement.getAttribute('style'));
          break;
        case scrollContainerElement:
          cloneContainerElement.setAttribute('style', scrollContainerElement.getAttribute('style'));
          break;
      }
    }
  });

  // start observing the scroll elements for `style` attribute changes
  this.mutationObserver.observe(scrollElement, { attributeFilter: ['style'], subtree: true });
}

销毁组件时,断开连接MutationObserver以避免内存泄漏。

ngOnDestroy() {
  // stop observing
  this.mutationObserver.disconnect();
}

这很棘手,并且全部基于使克隆的滚动条与原始滚动条保持同步,但到目前为止它对我的用例非常有效。

祝你好运


推荐阅读