Как рассчитать количество элементов flexbox в строке?
Сетка реализована с использованием Flexbox. Пример:
Количество строк в этом примере равно 4, потому что я установил ширину контейнера для демонстрационных целей. Но на самом деле он может меняться в зависимости от ширины контейнера (например, если пользователь изменяет размер окна). Попробуйте изменить размер окна вывода в этом примере, чтобы получить представление.
Всегда есть один активный элемент, отмеченный черной рамкой.
Используя JavaScript, я разрешаю пользователям перемещаться по предыдущему/следующему элементу с помощью стрелки влево/вправо. В моей реализации я просто уменьшаю/увеличиваю индекс активного элемента на 1.
Теперь я хочу, чтобы пользователи могли перемещаться вверх и вниз. Для этого мне просто нужно уменьшить/увеличить индекс активного элемента на <amount of items in a row>
. Но как вычислить это число, учитывая, что он зависит от ширины контейнера? Есть ли лучший способ реализовать функции "вверх-вниз"?
.grid {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 250px;
height: 200px;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div id="grid" class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответы
Ответ 1
(Для оптимального опыта лучше всего использовать интерактивные фрагменты на полной странице)
Вычисление количества элементов в строке
Вам нужно получить ширину элемента с его границей (в конце концов, если они установлены), тогда вам нужно получить внутреннюю ширину контейнера без заполнения. Имея эти 2 значения, вы делаете простое разделение, чтобы получить число элементов в строке.
Не забудьте рассмотреть случай, когда у вас есть только одна строка, поэтому вам нужно получить минимальное значение между общим количеством элементов и числом, которое вы получаете от подразделения.
//total number of element
var n_t = document.querySelectorAll('.item').length;
//width of an element
var w = parseInt(document.querySelector('.item').offsetWidth);
//full width of element with margin
var m = document.querySelector('.item').currentStyle || window.getComputedStyle(document.querySelector('.item'));
w = w + parseInt(m.marginLeft) + parseInt(m.marginRight);
//width of container
var w_c = parseInt(document.querySelector('.grid').offsetWidth);
//padding of container
var c = document.querySelector('.grid').currentStyle || window.getComputedStyle(document.querySelector('.grid'));
var p_c = parseInt(c.paddingLeft) + parseInt(c.paddingRight);
//nb element per row
var nb = Math.min(parseInt((w_c - p_c) / w),n_t);
console.log(nb);
window.addEventListener('resize', function(event){
//only the width of container will change
w_c = parseInt(document.querySelector('.grid').offsetWidth);
nb = Math.min(parseInt((w_c - p_c) / w),n_t);
console.log(nb);
});
.grid {
display: flex;
flex-wrap: wrap;
resize:horizontal;
align-content: flex-start;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 80px;
height: 80px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div id="grid" class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 2
Вопрос немного более сложный, чем поиск количества элементов в строке.
В конечном счете, мы хотим знать, есть ли элемент выше, ниже, слева и справа от активного элемента. И это должно учитывать случаи, когда нижняя строка является неполной. Например, в приведенном ниже примере активный элемент не имеет элемента выше, ниже или справа:
Но, чтобы определить, есть ли элемент выше/ниже/слева/справа от активного элемента, нам нужно знать, сколько элементов находится в строке.
Найдите количество элементов в строке
Чтобы получить количество элементов в строке, нам нужно:
-
itemWidth
- outerWidth
одного элемента, включая border
, padding
и margin
-
gridWidth
- innerWidth
сетки, исключая border
, padding
и margin
Чтобы рассчитать эти два значения с помощью обычного JavaScript, мы можем использовать:
const itemStyle = singleItem.currentStyle || window.getComputedStyle(active);
const itemWidth = singleItem.offsetWidth + parseFloat(itemStyle.marginLeft) + parseFloat(itemStyle.marginRight);
const gridStyle = grid.currentStyle || window.getComputedStyle(grid);
const gridWidth = grid.clientWidth - (parseFloat(gridStyle.paddingLeft) + parseFloat(gridStyle.paddingRight));
Затем мы можем вычислить количество элементов в строке, используя:
const numPerRow = Math.floor(gridWidth / itemWidth)
Примечание: это будет работать только для элементов однородного размера, и только если margin
определена в единицах px
.
Многое, много, много упрощенного подхода
Работа со всеми этими ширинами, а также прокладки, поля и границы действительно запутывают. Там гораздо, гораздо более простое решение.
Нам нужно только найти индекс элемента сетки, значение offsetTop
которого больше, чем первый элемент offsetTop
.
const grid = Array.from(document.querySelector("#grid").children);
const baseOffset = grid[0].offsetTop;
const breakIndex = grid.findIndex(item => item.offsetTop > baseOffset);
const numPerRow = (breakIndex === -1 ? grid.length : breakIndex);
Терминал в конце учитывает случаи, когда в сетке есть только один элемент и/или один ряд элементов.
const getNumPerRow = (selector) => {
const grid = Array.from(document.querySelector(selector).children);
const baseOffset = grid[0].offsetTop;
const breakIndex = grid.findIndex(item => item.offsetTop > baseOffset);
return (breakIndex === -1 ? grid.length : breakIndex);
}
.grid {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 400px;
background-color: #ddd;
padding: 10px 0 0 10px;
margin-top: 5px;
resize: horizontal;
overflow: auto;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<button onclick="alert(getNumPerRow('#grid'))">Get Num Per Row</button>
<div id="grid" class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 3
Единственный способ передвижения вверх и вниз, который возникает из-за менее нежелательного усложнения моих знаний, - это количество ящиков в строке и изменение индексов. Единственная проблема заключается в том, что вам нужно вычислить бокс-сечение как при загрузке окна, так и при изменении размера.
var boxPerRow=0;
function calculateBoxPerRow(){}
window.onload = calculateBoxPerRow;
window.onresize = calculateBoxPerRow;
Теперь, если вы хотите очень простой способ получить количество ящиков в строке, даже не заботясь о размере ни контейнера, ни полей, забудьте поля и прокладки, вы можете проверить, сколько ячеек выровнено с первым полем, сравнивающим offsetTop.
Свойство HTMLElement.offsetTop для чтения возвращает расстояние от текущего элемента относительно вершины узла offsetParent. [источник: developer.mozilla.orgl ]
Вы можете реализовать его, как показано ниже:
function calculateBoxPerRow(){
var boxes = document.querySelectorAll('.item');
if (boxes.length > 1) {
var i = 0, total = boxes.length, firstOffset = boxes[0].offsetTop;
while (++i < total && boxes[i].offsetTop == firstOffset);
boxPerRow = i;
}
}
Полный рабочий пример:
(function() {
var boxes = document.querySelectorAll('.item');
var boxPerRow = 0, currentBoxIndex = 0;
function calculateBoxPerRow() {
if (boxes.length > 1) {
var i = 0,
total = boxes.length,
firstOffset = boxes[0].offsetTop;
while (++i < total && boxes[i].offsetTop == firstOffset);
boxPerRow = i;
}
}
window.onload = calculateBoxPerRow;
window.onresize = calculateBoxPerRow;
function focusBox(index) {
if (index >= 0 && index < boxes.length) {
if (currentBoxIndex > -1) boxes[currentBoxIndex].classList.remove('active');
boxes[index].classList.add('active');
currentBoxIndex = index;
}
}
document.body.addEventListener("keyup", function(event) {
switch (event.keyCode) {
case 37:
focusBox(currentBoxIndex - 1);
break;
case 39:
focusBox(currentBoxIndex + 1);
break;
case 38:
focusBox(currentBoxIndex - boxPerRow);
break;
case 40:
focusBox(currentBoxIndex + boxPerRow);
break;
}
});
})();
.grid {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 50%;
height: 200px;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div>[You need to click on this page so that it can recieve the arrow keys]</div>
<div id="grid" class="grid">
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 4
Чтобы поддерживать перемещение вверх, вниз, влево и вправо, вам не нужно знать, сколько ящиков есть в строке, вам просто нужно вычислить, есть ли над ним, внизу, слева или справа от активной коробки,
Перемещение влево и вправо прост, как вы заметили, - просто проверьте, имеет ли активная ячейка previousSiblingElement
nextSiblingElement
или следующий nextSiblingElement
. Для вверх и вниз, вы можете использовать текущую активную форму в качестве опорной точки и сравнить его с другой коробкой getBoundingClientRect()
s, метод DOM, который возвращает geomoetry элемента относительно к браузерам просмотра.
При попытке подняться вверх, начните с якоря и пересчитайте предметы по направлению к 0. При движении вниз, начните с якоря и подсчитывайте до конца количества предметов. Это связано с тем, что при перемещении мы занимаемся только коробками перед активным ящиком, а при спуске мы заботимся о коробках после него. Все, что нам нужно искать, это коробка, которая имеет ту же левую позицию с более высокой или нижней верхней позицией.
Ниже приведен пример, который прослушивает событие keydown в window
и будет перемещать активное состояние в соответствии с нажатой клавишей со стрелкой. Это определенно можно сделать более сухим, но я разделил четыре случая, чтобы вы могли видеть точную логику в каждом. Вы можете удерживать клавиши со стрелками вниз, чтобы поле двигалось непрерывно, и вы можете видеть его очень эффектным. И я обновил ваш JSBin своим решением здесь: http://jsbin.com/senigudoqu/1/edit?html,css,js,output
const items = document.querySelectorAll('.item');
let activeItem = document.querySelector('.item.active');
function updateActiveItem(event) {
let index;
let rect1;
let rect2;
switch (event.key) {
case 'ArrowDown':
index = Array.prototype.indexOf.call(items, activeItem);
rect1 = activeItem.getBoundingClientRect();
for (let i = index; i < items.length; i++) {
rect2 = items[i].getBoundingClientRect();
if (rect1.x === rect2.x && rect1.y < rect2.y) {
items[i].classList.add('active');
activeItem.classList.remove('active');
activeItem = items[i];
return;
}
}
break;
case 'ArrowUp':
index = Array.prototype.indexOf.call(items, activeItem);
rect1 = activeItem.getBoundingClientRect();
for (let i = index; i >= 0; i--) {
rect2 = items[i].getBoundingClientRect();
if (rect1.x === rect2.x && rect1.y > rect2.y) {
items[i].classList.add('active');
activeItem.classList.remove('active');
activeItem = items[i];
return;
}
}
break;
case 'ArrowLeft':
let prev = activeItem.previousElementSibling;
if (prev) {
prev.classList.add('active');
activeItem.classList.remove('active');
activeItem = prev;
}
break;
case 'ArrowRight':
let next = activeItem.nextElementSibling;
if (next) {
next.classList.add('active');
activeItem.classList.remove('active');
activeItem = next;
}
break;
default:
return;
}
}
window.addEventListener('keydown', updateActiveItem);
.grid {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div id="grid" class="grid">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 5
Хотя вы можете рассчитать, какой элемент вы ищете, я предлагаю вам найти элемент ниже. Преимущество этого заключается в том, что он даже будет работать, если ваши элементы не имеют одинаковой ширины.
Поэтому давайте подумаем об атрибутах элемента ниже. По сути, это первый элемент с более высоким offsetTop
и тем же offsetLeft
. Вы можете сделать что-то подобное, чтобы найти элемент ontop:
const active = document.querySelector('.item.active');
const all = [...document.querySelectorAll('.item')]
const below = all
.filter(c => c.offsetTop > active.offsetTop)
.find(c => c.offsetLeft >= active.offsetLeft)
const ontop = [...all].reverse()
.filter(c => c.offsetTop < active.offsetTop)
.find(c => c.offsetLeft >= active.offsetLeft)
Ответ 6
В этом примере предполагается, что конечные точки движения ограничены. Кроме того, при переходе от второй к последней строке до последней строки, но в последней строке меньше столбцов, она будет перемещаться в последний столбец последней строки.
Это решение отслеживает строки/столбцы и использует объект сетки, чтобы отслеживать, где находятся элементы. Позиции будут обновляться в объекте сетки при изменении размера страницы.
(вы можете увидеть обновление упаковки в действии в полноэкранном режиме)
var items = document.querySelectorAll(".item");
var grid = {}; // keys: row, values: index of div in items variable
var row, col, numRows;
// called only onload and onresize
function populateGrid() {
grid = {};
var prevTop = -99;
var row = -1;
for(idx in items) {
if(isNaN(idx)) continue;
if(items[idx].offsetTop !== prevTop) {
prevTop = items[idx].offsetTop;
row++;
grid[row] = [];
}
grid[row].push(idx);
}
setActiveRowAndCol();
numRows = Object.keys(grid).length
}
// changes active state from one element to another
function updateActiveState(oldElem, newElem) {
oldElem.classList.remove('active');
newElem.classList.add('active');
}
// only called from populateGrid to get new row/col of active element (in case of wrap)
function setActiveRowAndCol() {
var activeIdx = -1;
for(var idx in items) {
if(items[idx].className == "item active")
activeIdx = idx;
}
for(var key in grid) {
var gridIdx = grid[key].indexOf(activeIdx);
if(gridIdx > -1) {
row = key;
col = gridIdx;
}
}
}
function moveUp() {
if(0 < row) {
var oldElem = items[grid[row][col]];
row--;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
function moveDown() {
if(row < numRows - 1) {
var oldElem = items[grid[row][col]];
row++;
var rowLength = grid[row].length
var newElem;
if(rowLength-1 < col) {
newElem = items[grid[row][rowLength-1]]
col = rowLength-1;
} else {
newElem = items[grid[row][col]];
}
updateActiveState(oldElem, newElem);
}
}
function moveLeft() {
if(0 < col) {
var oldElem = items[grid[row][col]];
col--;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
function moveRight() {
if(col < grid[row].length - 1) {
var oldElem = items[grid[row][col]];
col++;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
document.onload = populateGrid();
window.addEventListener("resize", populateGrid);
document.addEventListener('keydown', function(e) {
e = e || window.event;
if (e.keyCode == '38') {
moveUp();
} else if (e.keyCode == '40') {
moveDown();
} else if (e.keyCode == '37') {
moveLeft();
} else if (e.keyCode == '39') {
moveRight();
}
});
.grid {
display: flex;
flex-wrap: wrap;
resize: horizontal;
align-content: flex-start;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div id="grid" class="grid">
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 7
Я знаю, что это не совсем то, о чем просит ОП, но я хотел показать возможную альтернативу (зависит от варианта использования).
Вместо использования CSS flexbox существует также более новая CSS-сетка, которая фактически содержит столбцы и строки. Таким образом, преобразуя структуру в сетку и используя некоторый JS для прослушивания нажатых клавиш, активный элемент может быть перемещен (см. Неполный рабочий пример ниже).
var x = 1, y = 1;
document.addEventListener('keydown', function(event) {
const key = event.key;
// "ArrowRight", "ArrowLeft", "ArrowUp", or "ArrowDown"
console.log(key);
if (key == "ArrowRight") {
x++;
}
if (key == "ArrowLeft") {
x--;
if (x < 1) {
x = 1;
}
}
if (key == "ArrowUp") {
y--;
if (y < 1) {
y = 1;
}
}
if (key == "ArrowDown") {
y++;
}
document.querySelector('.active').style.gridColumnStart = x;
document.querySelector('.active').style.gridRowStart = y;
});
.grid {
display: grid;
grid-template-columns: repeat(auto-fill,50px);
grid-template-rows: auto;
grid-gap: 10px;
width: 250px;
height: 200px;
background-color: #ddd;
padding: 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
display: flex;
justify-content: center;
align-items: center;
}
.active {
outline: 5px solid black;
grid-column-start: 1;
grid-column-end: span 1;
grid-row-start: 1;
grid-row-end: span 1;
}
<div id="grid" class="grid">
<div class="item active">A1</div>
<div class="item">A2</div>
<div class="item">A3</div>
<div class="item">A4</div>
<div class="item">B1</div>
<div class="item">B2</div>
<div class="item">B3</div>
<div class="item">B4</div>
<div class="item">C1</div>
<div class="item">C2</div>
</div>
Ответ 8
Вы можете использовать Array.prototype.filter(), чтобы сделать это довольно аккуратно. Чтобы получить количество элементов в строке, используйте эту функцию. Перейдите в селектор CSS, который вы хотите использовать (в этом случае.item). Когда у вас есть размер строки, стрелка навигация проста.
function getRowSize( cssSelector ) {
var firstTop = document.querySelector( cssSelector ).offsetTop;
// Sets rowArray to be an array of the nodes (divs) in the 1st row.
var rowArray = Array.prototype.filter.call(document.querySelectorAll( cssSelector ), function(element){
if( element.offsetTop == firstTop ) return element;
});
// Return the amount of items in a row.
return rowArray.length;
}
Примеры
Демо-версия CodePen: https://codepen.io/gtlitc/pen/EExXQE
Интерактивная демонстрация, отображающая размер строки и количество перемещений. http://www.smallblue.net/demo/49043684/
объяснение
Во-первых, функция устанавливает переменную firstTop
как offsetTop
самого первого узла.
Затем функция создает массив rowArray
узлов в первой строке (если возможна перемещение вверх и вниз, первая строка всегда будет полной длиной строки).
Это делается путем вызова (заимствования) функции фильтра из прототипа Array. Мы не можем просто вызвать функцию фильтра в списке узлов, который возвращается QSA (селектор запросов), поскольку браузеры возвращают списки узлов вместо массивов, а списки узлов не являются подходящими массивами.
Затем оператор if просто фильтрует все узлы и возвращает только те, которые имеют тот же самый offsetTop
что и первый узел. т.е. всех узлов в первой строке.
Теперь у нас есть массив, из которого мы можем определить длину строки.
Я пропустил реализацию обхода DOM, поскольку это просто, используя либо чистый Javascript, либо JQuery и т.д., И не был частью вопроса OP. Я хотел бы только отметить, что важно проверить, должен ли элемент, который вы собираетесь переместить, существовать до его перемещения.
Эта функция будет работать с любым способом компоновки. Flexbox, float, CSS grid, независимо от будущего.
Рекомендации
Почему document.querySelectorAll возвращает StaticNodeList, а не реальный массив?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Ответ 9
offsetTop
- популярный метод определения y-позиции элемента.
Если два смежных элемента sibling имеют одинаковое положение y, мы можем с уверенностью предположить, что они визуально находятся в одной строке (так как все элементы имеют одинаковую высоту).
Таким образом, мы можем начать подсчет количества элементов в строке, сравнивая их y-позиции один за другим. Мы перестаем считать, как только у нас заканчиваются элементы, или мы сталкиваемся с соседним братом с другой y-позицией.
function getCountOfItemsInRow() {
let grid = document.getElementById('grid').children; //assumes #grid exists in dom
let n = 0; // Zero items when grid is empty
// If the grid has items, we assume the 0th element is in the first row, and begin counting at 1
if (grid.length > 0) {
n = 1;
// While the nth item has the same height as the previous item, count it as an item in the row.
while (grid[n] && grid[n].offsetTop === grid[n - 1].offsetTop) {
n++;
}
}
return n;
}
Ответ 10
В этом примере предполагается, что конечные точки движения ограничены. Кроме того, при переходе от второй к последней строке до последней строки, но в последней строке меньше столбцов, она будет перемещаться в последний столбец последней строки.
Это решение отслеживает строки/столбцы и использует объект сетки, чтобы отслеживать, где находятся элементы.
var items = document.querySelectorAll(".item");
var grid = {}; // keys: row, values: index of div in items variable
var row, col, numRows;
// called only onload and onresize
function populateGrid() {
grid = {};
var prevTop = -99;
var row = -1;
for(idx in items) {
if(isNaN(idx)) continue;
if(items[idx].offsetTop !== prevTop) {
prevTop = items[idx].offsetTop;
row++;
grid[row] = [];
}
grid[row].push(idx);
}
setActiveRowAndCol();
numRows = Object.keys(grid).length
}
// changes active state from one element to another
function updateActiveState(oldElem, newElem) {
oldElem.classList.remove('active');
newElem.classList.add('active');
}
// only called from populateGrid to get new row/col of active element (in case of wrap)
function setActiveRowAndCol() {
var activeIdx = -1;
for(var idx in items) {
if(items[idx].className == "item active")
activeIdx = idx;
}
for(var key in grid) {
var gridIdx = grid[key].indexOf(activeIdx);
if(gridIdx > -1) {
row = key;
col = gridIdx;
}
}
}
function moveUp() {
if(0 < row) {
var oldElem = items[grid[row][col]];
row--;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
function moveDown() {
if(row < numRows - 1) {
var oldElem = items[grid[row][col]];
row++;
var rowLength = grid[row].length
var newElem;
if(rowLength-1 < col) {
newElem = items[grid[row][rowLength-1]]
col = rowLength-1;
} else {
newElem = items[grid[row][col]];
}
updateActiveState(oldElem, newElem);
}
}
function moveLeft() {
if(0 < col) {
var oldElem = items[grid[row][col]];
col--;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
function moveRight() {
if(col < grid[row].length - 1) {
var oldElem = items[grid[row][col]];
col++;
var newElem = items[grid[row][col]];
updateActiveState(oldElem, newElem);
}
}
document.onload = populateGrid();
window.addEventListener("resize", populateGrid);
document.addEventListener('keydown', function(e) {
e = e || window.event;
if (e.keyCode == '38') {
moveUp();
} else if (e.keyCode == '40') {
moveDown();
} else if (e.keyCode == '37') {
moveLeft();
} else if (e.keyCode == '39') {
moveRight();
}
});
.grid {
display: flex;
flex-wrap: wrap;
resize: horizontal;
align-content: flex-start;
background-color: #ddd;
padding: 10px 0 0 10px;
}
.item {
width: 50px;
height: 50px;
background-color: red;
margin: 0 10px 10px 0;
}
.active.item {
outline: 5px solid black;
}
<div id="grid" class="grid">
<div class="item active"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Ответ 11
Если вы используете JQuery и уверены, что ваши объекты сетки выровнены по вертикали, это может сделать трюк.
Я не тестировал его, но он должен работать (путем подсчета столбцов)
function countColumns(){
var objects = $(".grid-object"); // choose a unique class name here
var columns = []
for(var i=0;i<objects.length;i++){
var pos = $(objects[i]).position().left
if(columns.indexOf(pos) < 1) columns.push(pos);
}
return columns.length
}