Лучший способ представить редактируемые таблицы - PullRequest
0 голосов
/ 10 июля 2019

Я унаследовал работу по поддержке и разработке внутренней системы ведения журналов для регистрации инвентаризации в таблицах на локальном веб-сайте. Это веб-сайт, созданный на PHP, использующий jquery и handontable для вывода данных из базы данных MySQL. Все поля в таблице доступны для редактирования пользователями.

Сегодня загрузка данных может быть медленной (10-15 секунд в самых больших таблицах), что в основном связано с циклами, используемыми для заполнения таблицы и настройки размеров столбцов.

Как вы думаете, что будет лучшим способом исправить эту проблему? Должен ли я сократить время загрузки, исправляя циклы, и сохранить handsontable как библиотеку таблиц? Или я должен отказаться от старого решения и реализовать что-то новое?

Спасибо:)

1 Ответ

0 голосов
/ 10 июля 2019

EDIT

Я только что видел, что вы используете handsontable, поэтому мой ответ на самом деле не дает решения, так как handsontable уже использует своего рода виртуализацию списка. Я все равно оставлю свой ответ


Оригинальный ответ

Что вы, вероятно, можете сделать, это какая-то виртуализация списка, хотя это может быть немного сложно с элементами таблицы, потому что вам нужно абсолютное позиционирование и контроль высот. Также обычно предполагается, что все строки имеют одинаковую высоту.

Общая идея заключается в том, что вы хотите беспокоиться только о том, что отображается на экране. Предполагая, что вы можете разместить 50 строк в окне просмотра в любое время, вы измеряете и обновляете 650 строк, которые не имеют значения. Если у вас 500000 строк, как в скрипке, ваша проблема будет экспоненциально неуправляемой.

Не зная, что именно вы делаете, вот очень общий подход к проблеме:

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, я не использовал его в течение многих лет.

См. Скрипку

Есть несколько предостережений при таком подходе. Основной из них, являющийся высотой строки, должен быть одинаковым для всех строк, что недопустимо для ряда ситуаций. Он также опирается на фиксированную высоту контейнера, хотя гибкая модель может обойти это.

...