呈现可编辑表格的最佳方法

时间:2019-07-10 06:08:10

标签: javascript php jquery handsontable

我继承了维护和开发内部日记系统的工作,该系统用于在本地网站上的表中注册库存。这是一个用PHP创建的网站,使用jquery和handontable来列出MySQL数据库中的数据。表格中的所有字段均可由用户编辑。

如今,数据加载可能很慢(在最大的表中为10-15秒),这主要是由于用于填充表和调整列大小的循环所致。

您认为什么是解决此问题的最佳方法?我是否应该通过修复循环来减少加载时间,并保持handontable作为表库?还是应该废弃旧的解决方案并实施新的解决方案?

谢谢:)

1 个答案:

答案 0 :(得分:0)

编辑

我刚刚看到您正在使用handontable,所以我的回答并没有真正提供解决方案,因为handsontable已经使用了一种列表虚拟化。我还是留下我的答案


原始答案

您可能可以做的是某种形式的列表虚拟化,尽管对于表格元素来说这可能有些棘手,因为您需要绝对定位和控制高度。通常还假设所有行的高度都相同。

通常的想法是,您只需要渲染屏幕上当前显示的内容即可。假设您随时可以在视口中容纳50行,那么您正在测量和更新650行无关紧要。如果您有50万行,就像在小提琴中一样,那么您的问题将成指数级地失控。

在不知道自己到底在做什么的情况下,这是一种非常通用的解决方法:

var elements = [];
var maxLength = 500000; // Number of elements we're going to generate
var itemHeight = 20; // We need a static row height for this to work
var totalHeight = itemHeight * maxLength; // The total height of the content
var $scrollContainer = $('#scroller-container'); // The container that will scroll
var $scrollContent = $('#scroller-contents'); // The content container for our items.

// We need to set the total height of the content so that absolute positioning works and the container receives the correctly sized scroll bar.
$scrollContent.css({ height: `${totalHeight}px` });

// Generate elements.
for (let i = 0; i < maxLength; i++) {
    elements.push({
    name: `item_${i}`,
    value: `value_${i + 100}`
  });
}

// By taking some measurements we will find out
// here exactly what items need to be rendered.
function obtainRenderableItems () {
  // The size of our scrollable container
  var containerHeight = $scrollContainer.height();

  // How many items will fit inside the viewable area of our scrollable container
  var viewport_count = Math.ceil(containerHeight / itemHeight);

  // Where is it currently scrolled to.
  var scrollPosition = $scrollContainer.scrollTop();

  // The index of the first item in the viewable area
  var start = Math.floor(scrollPosition / itemHeight);

  // This calculation gives us a number of items to buffer on either side
  // which prevents some janky behaviour when scrolling over yet unrendered items
  var preScan = start - viewport_count <= 0 ? 0 : start - viewport_count;

  // Basically we get the elements visible on the viewports by the current start
  // index, and a buffer at the beginning and the end of the same amount of items
  // in the viewport.
  return elements.slice(preScan, preScan + (viewport_count * 3)).map((element, index) => {
    return [preScan + index, element];
  });
};

// Convert it to HTML, you can do whatever here, demo only.
function generateHTML (elements) {
    return elements.map(el => {
    let div = document.createElement('div');
    div.className = 'element';
    div.style.height = `${itemHeight}px`;
    div.style.top = `${el[0] * itemHeight}px`;

    div.innerHTML = `${el[1].name} - ${el[1].value}`;

    return div.outerHTML;
  }).join('');
}

// When we scroll we recalculate what items need to be shown and rerender them
// inside the page.
function onScroll (event) {
    let items = obtainRenderableItems();
  let htmlContent = generateHTML(items);

  $scrollContent.html(htmlContent);
}

$scrollContainer.scroll(onScroll);

// Run at the beginning
onScroll();

上面的jQuery示例基于我为此目的编写的React组件。您必须原谅我多年没有使用过的jQuery。

See the fiddle

此方法有许多警告。主要的问题是所有行的行高必须相同,这在许多情况下都不可行。尽管flex模型可以解决这个问题,但它也依赖于固定的容器高度。