Gridstack.js предоставляет возможность создавать динамические, перетаскиваемые и масштабируемые сетки элементов в веб-приложениях. Когда используется вложенная сетка (nested grid), каждый элемент родительской сетки может содержать собственную дочернюю сетку. Для правильного восстановления интерфейса после перезагрузки страницы или изменения состояния необходимо сохранять позицию, размеры и порядок элементов как родительской, так и дочерней сеток.
Gridstack.js использует объекты для описания состояния виджетов. Каждый элемент имеет стандартные свойства:
x – позиция по горизонтали (номер колонки)y – позиция по вертикали (номер ряда)w – ширина элемента в колонкахh – высота элемента в рядахid – уникальный идентификатор элемента (рекомендуется
для восстановления)minW, minH, maxW,
maxH – ограничения размеровcontent или другие кастомные свойства для хранения
специфической информацииДля вложенных сеток важно также сохранять состояние дочерних сеток, что превращает состояние в рекурсивную структуру. Пример объекта состояния:
[
{
"id": "parent1",
"x": 0,
"y": 0,
"w": 6,
"h": 4,
"nestedGrid": [
{
"id": "child1",
"x": 0,
"y": 0,
"w": 3,
"h": 2
},
{
"id": "child2",
"x": 3,
"y": 0,
"w": 3,
"h": 2
}
]
},
{
"id": "parent2",
"x": 6,
"y": 0,
"w": 6,
"h": 4
}
]
Для получения текущего состояния Gridstack используется метод
save() или save(false) (в зависимости от
версии):
let grid = GridStack.init();
let state = grid.save(); // Возвращает массив объектов
При использовании вложенных сеток необходимо рекурсивно обрабатывать элементы, которые содержат дочерние сетки. Например:
function saveNestedGrid(grid) {
return grid.save().map(widget => {
let nestedGridEl = widget.el.querySelector('.grid-stack');
if (nestedGridEl) {
let nestedGrid = GridStack.getGrid(nestedGridEl);
widget.nestedGrid = saveNestedGrid(nestedGrid);
}
return widget;
});
}
let fullState = saveNestedGrid(GridStack.getGrids()[0]);
Для восстановления состояния используется метод
load():
grid.load(savedState);
Для вложенных сеток необходимо загружать состояние рекурсивно:
function loadNestedGrid(grid, state) {
grid.removeAll();
grid.load(state.map(widget => {
let w = { ...widget };
delete w.nestedGrid; // удаляем вложенную сетку для загрузки
return w;
}));
state.forEach(widget => {
if (widget.nestedGrid) {
let el = grid.getCellFromNode(document.getElementById(widget.id));
let nestedGridEl = el.querySelector('.grid-stack');
let nestedGrid = GridStack.init({ staticGrid: false }, nestedGridEl);
loadNestedGrid(nestedGrid, widget.nestedGrid);
}
});
}
loadNestedGrid(GridStack.getGrids()[0], fullState);
Состояние удобно сохранять в localStorage или
IndexedDB для восстановления после перезагрузки:
localStorage.setItem('gridState', JSON.stringify(fullState));
let savedState = JSON.parse(localStorage.getItem('gridState'));
Важно сериализовать только те данные, которые необходимы для восстановления позиции и размеров, чтобы уменьшить объем хранимой информации.
Gridstack.js поддерживает события change и
added, которые позволяют автоматически отслеживать
изменения:
grid.on('change', function(event, items) {
let state = saveNestedGrid(grid);
localStorage.setItem('gridState', JSON.stringify(state));
});
Для вложенных сеток рекомендуется также подписываться на события дочерних сеток:
function attachNestedSave(grid) {
grid.on('change', () => {
let state = saveNestedGrid(GridStack.getGrids()[0]);
localStorage.setItem('gridState', JSON.stringify(state));
});
grid.engine.nodes.forEach(node => {
let nestedEl = node.el.querySelector('.grid-stack');
if (nestedEl) {
let nestedGrid = GridStack.getGrid(nestedEl);
attachNestedSave(nestedGrid);
}
});
}
attachNestedSave(GridStack.getGrids()[0]);
save() и load() могут изменяться между
версиями.change, чтобы уменьшить частоту записи состояния в
localStorage.<div class="grid-stack" id="parentGrid">
<div class="grid-stack-item" id="parent1">
<div class="grid-stack-item-content">
<div class="grid-stack nested-grid"></div>
</div>
</div>
<div class="grid-stack-item" id="parent2">
<div class="grid-stack-item-content"></div>
</div>
</div>
Инициализация:
let parentGrid = GridStack.init({ cellHeight: 80 }, '#parentGrid');
parentGrid.engine.nodes.forEach(node => {
let nestedEl = node.el.querySelector('.nested-grid');
if (nestedEl) {
GridStack.init({ cellHeight: 40 }, nestedEl);
}
});
Эта структура обеспечивает корректное хранение и восстановление состояния как родительских, так и вложенных сеток, обеспечивая динамичность интерфейса и сохранность пользовательских изменений.