Кликать только на верхний, нижний, соседний элемент в 2d массиве
Есть такой код, 2d массив:
let app = document.getElementById('app');
let table = document.createElement('div');
table.classList.add('table');
app.appendChild(table);
const BASE = 9;
let arrNum = [];
for(let iNum = 1; iNum < 20; iNum ++ ) {
if(iNum%10 === 0) continue;
let strNum = iNum.toString();
arrNum.push(...strNum);
}
let n = arrNum.length;
let x = BASE;
let y = Math.floor(n / BASE);
for(let iy = 0; iy < y; iy++){
let tr = document.createElement('div');
tr.classList.add('tr');
table.appendChild(tr);
for(let ix = 0; ix < x; ix++){
let td = document.createElement('div');
td.classList.add('td');
td.dataset.x = ix;
td.dataset.y = iy;
tr.appendChild(td);
}
}
const nums = document.querySelectorAll('.td');
arrNum.forEach((num, i) => {
nums[i].innerHTML = num;
});
let isNum = false;
let firstNum, secondNum;
function flipNum(){
if(this === firstNum) return;
this.classList.add('select');
if(!isNum) {
isNum = true;
firstNum = this;
return;
}
secondNum = this;
getIndex();
checkForMatch();
}
function getIndex(){
//console.log(firstNum.dataset.x + ' ' + firstNum.dataset.y);
}
function checkForMatch() {
let firstNumVal = +firstNum.innerHTML;
let secondNumVal = +secondNum.innerHTML;
let isMatch = firstNumVal + secondNumVal === BASE + 1 || firstNumVal === secondNumVal;
console.log(isMatch);
isMatch ? disableNum() : resetMatch();
}
function disableNum(){
firstNum.removeEventListener('click', flipNum);
secondNum.removeEventListener('click', flipNum);
firstNum.classList.add('match');
secondNum.classList.add('match');
resetNum();
}
function resetMatch(){
firstNum.classList.remove('select');
secondNum.classList.remove('select');
resetNum();
}
function resetNum(){
isNum = false;
firstNum = null;
secondNum = null;
}
nums.forEach(num => num.addEventListener('click', flipNum));
* {
box-sizing: border-box;
}
html,
body {
padding: 0;
margin: 0;
}
.table {
max-width: 500px;
margin: 2rem auto;
}
.tr {
display: flex;
}
.td {
width: calc(100% / 9);
height: 2.5rem;
line-height: 2.5rem;
text-align: center;
cursor: pointer;
border: 1px solid;
}
.select {
background: #8BC34A;
}
.match {
background: #bdbdbd;
}
<div id="app"></div>
Вопрос: как можно реализовать клик только по соседней ячейке (ввеху, внизу, слева, справа), как запретить клик по диагональной ячейке?
Ответы (2 шт):
Автор решения: OPTIMUS PRIME
→ Ссылка
Суть задачи: Из блоков создан некий прямоугольник A x B, надо научиться находить соседние клетки каждого блока. Количество клеток в каждой строке заранее известно, остается немного поработоть с номером кликнутой кнопки:
let html = new Array(27).fill(0).map((_,i) => `<div class="box">${ i }</div>`).join("");
document.body.insertAdjacentHTML("beforeEnd", html);
// Создает блоки, не важно.
/***/
let boxes = document.querySelectorAll(".box");
const COLS = 9;
document.addEventListener("click", function(e) {
if (e.target.classList.contains("box")) box_onclick(e.target);
});
function box_onclick(box) {
console.clear();
if (box.classList.contains("available")) {
console.log("Доступно");
} else {
console.log("Не доступно");
}
/***/
boxes.forEach(e => e.classList.remove("active", "available"));
box.classList.add("active");
highlight_surrounding_boxes(box);
}
function highlight_surrounding_boxes(box) {
let index = Array.prototype.indexOf.call(boxes, box);
// Номер кликнутой клетки среди всех 27 boxes
let surrounding_indexes = [
/* top */ index - COLS >= 0 && index - COLS ,
/* right */ (index + 1) % COLS != 0 && index + 1 ,
/* bottom */ index + COLS < boxes.length && index + COLS ,
/* left */ index % COLS != 0 && index - 1 ,
];
/* Особенность логического "И" в JS:
false && 17 === false
true && 17 === 17
Если поставленное условие выдаст false, результатом всего
выражения будет false. Иначе - число, нужный индекс.
*/
console.log( JSON.stringify(surrounding_indexes) );
surrounding_indexes.forEach(
index => typeof index == "number" && boxes[index].classList.add("available")
); // Если index не число (сравнение выдаст false), вторая часть не выполнится.
}
.box {
display: inline-block;
width: 10vw;
margin: 1px;
padding: 5px;
border: 3px solid orange;
box-sizing: border-box;
cursor: pointer;
}
.box.available {
background-color: #ddd;
}
.box.active {
background-color: orange;
}
Автор решения: Grundy
→ Ссылка
Соседние клетки определяются тем, что их координаты отличаются на единицу.
Если брать только горизонтальное и вертикальное направление, то отличаться должна только одна координата, либо x либо y, друга должна совпадать.
Отсюда возникает следующая проверка
(first.x === second.x && Math.abs(first.y - second.y) === 1) // либо совпадают `x`, а `y` отличаются на 1 (верх либо низ)
(first.y === second.y && Math.abs(first.x - second.x) === 1) // либо совпадают `y`, а `x` отличаются на 1 (лево либо право)
В итоге код может выглядеть так:
let app = document.getElementById('app');
let table = document.createElement('div');
table.classList.add('table');
app.appendChild(table);
const BASE = 9;
let arrNum = [];
for (let iNum = 1; iNum < 20; iNum++) {
if (iNum % 10 === 0) continue;
let strNum = iNum.toString();
arrNum.push(...strNum);
}
let n = arrNum.length;
let x = BASE;
let y = Math.floor(n / BASE);
for (let iy = 0; iy < y; iy++) {
let tr = document.createElement('div');
tr.classList.add('tr');
table.appendChild(tr);
for (let ix = 0; ix < x; ix++) {
let td = document.createElement('div');
td.classList.add('td');
td.dataset.x = ix;
td.dataset.y = iy;
tr.appendChild(td);
}
}
const nums = document.querySelectorAll('.td');
arrNum.forEach((num, i) => {
nums[i].innerHTML = num;
});
let isNum = false;
let firstNum, secondNum;
function flipNum() {
if (this === firstNum) return;
this.classList.add('select');
if (!isNum) {
isNum = true;
firstNum = this;
return;
}
secondNum = this;
var isMatch = checkIndex() && checkForMatch();
if (isMatch) {
disableNum();
} else {
resetMatch();
}
}
function checkIndex() {
let first = {
x: +firstNum.dataset.x,
y: +firstNum.dataset.y
};
let second = {
x: +secondNum.dataset.x,
y: +secondNum.dataset.y
};
return (first.x === second.x && Math.abs(first.y - second.y) === 1) ||
(first.y === second.y && Math.abs(first.x - second.x) === 1);
}
function checkForMatch() {
let firstNumVal = +firstNum.innerHTML;
let secondNumVal = +secondNum.innerHTML;
return firstNumVal + secondNumVal === BASE + 1 || firstNumVal === secondNumVal;
}
function disableNum() {
firstNum.removeEventListener('click', flipNum);
secondNum.removeEventListener('click', flipNum);
firstNum.classList.add('match');
secondNum.classList.add('match');
resetNum();
}
function resetMatch() {
firstNum.classList.remove('select');
secondNum.classList.remove('select');
resetNum();
}
function resetNum() {
isNum = false;
firstNum = null;
secondNum = null;
}
nums.forEach(num => num.addEventListener('click', flipNum));
* {
box-sizing: border-box;
}
html,
body {
padding: 0;
margin: 0;
}
.table {
max-width: 500px;
margin: 2rem auto;
}
.tr {
display: flex;
}
.td {
width: calc(100% / 9);
height: 2.5rem;
line-height: 2.5rem;
text-align: center;
cursor: pointer;
border: 1px solid;
}
.select {
background: #8BC34A;
}
.match {
background: #bdbdbd;
}
<div id="app"></div>