Anonymous
Ввод кроссворда в JavaScript зависает, и фокус не перемещается на следующую ячейку
Сообщение
Anonymous » 30 ноя 2025, 03:00
Проблема
Когда я ввожу букву в ячейку, фокус не перемещается на следующую ячейку в слове.
После ввода буквы вся система ввода перестает отвечать — я не могу вводить больше букв, удалять их или нажимать на другие ячейки.
Ощущение, будто обработчик событий выдает ошибку и прекращает дальнейшее выполнение.
Думаю, все проблемы в renderGrid(), но я не знаю, где именно они.
(у меня все html-элементы написаны правильно)
Код: Выделить всё
const GRID_ROWS = 10;
const GRID_COLS = 10;
const WORDS = [
// Across
{ word: 'READ', clue: 'To look at and comprehend written words', row: 0, col: 0, direction: 'across', id: 1 },
{ word: 'EASY', clue: 'Not difficult', row: 2, col: 2, direction: 'across', id: 2 },
{ word: 'NOTE', clue: 'A short written message', row: 4, col: 4, direction: 'across', id: 3 },
{ word: 'GAME', clue: 'An activity for fun or competition', row: 6, col: 6, direction: 'across', id: 4 },
// Down
{ word: 'RENT', clue: 'To pay for the use of something', row: 0, col: 0, direction: 'down', id: 5 },
{ word: 'DEAN', clue: 'A college official', row: 0, col: 2, direction: 'down', id: 6 },
{ word: 'SONG', clue: 'A musical composition', row: 2, col: 4, direction: 'down', id: 7 },
{ word: 'MEGA', clue: 'Very large', row: 4, col: 6, direction: 'down', id: 8 },
];
let grid = [];
let selectedWordId = null;
let completedWords = new Set();
function createGrid() {
grid = Array.from({ length: GRID_ROWS }, (_, r) =>
Array.from({ length: GRID_COLS }, (_, c) => ({
row: r,
col: c,
letter: null,
value: '',
words: []
}))
);
WORDS.forEach(wordObj => {
let r = wordObj.row, c = wordObj.col;
for (let i = 0; i < wordObj.word.length; i++) {
const cell = grid[r][c];
cell.letter = wordObj.word[i];
cell.words.push(wordObj.id);
if (wordObj.direction === 'across') c++;
else r++;
}
});
}
function renderGrid() {
const table = document.getElementById('crosswordGrid');
table.innerHTML = '';
for (let r = 0; r < GRID_ROWS; r++) {
const tr = document.createElement('tr');
for (let c = 0; c < GRID_COLS; c++) {
const cell = grid[r][c];
const td = document.createElement('td');
if (cell.letter) {
const input = document.createElement('input');
input.type = 'text';
input.maxLength = 1;
input.className = 'crossword-cell';
input.value = cell.value;
input.dataset.row = r;
input.dataset.col = c;
input.onfocus = () => selectCell(r, c);
input.oninput = e => handleInput(e, r, c);
td.appendChild(input);
} else {
td.className = 'cell-blocked';
}
tr.appendChild(td);
}
table.appendChild(tr);
}
}
function renderClues() {
const acrossDiv = document.getElementById('acrossClues');
const downDiv = document.getElementById('downClues');
acrossDiv.innerHTML = '';
downDiv.innerHTML = '';
WORDS.forEach(word => {
const clueDiv = document.createElement('div');
clueDiv.className = 'clue' + (selectedWordId === word.id ? ' selected' : '') + (completedWords.has(word.id) ? ' completed' : '');
clueDiv.textContent = word.clue;
clueDiv.onclick = () => selectWord(word.id);
if (word.direction === 'across') acrossDiv.appendChild(clueDiv);
else downDiv.appendChild(clueDiv);
});
}
function selectWord(wordId) {
selectedWordId = wordId;
renderClues();
// Focus first cell of the word
const word = WORDS.find(w => w.id === wordId);
if (word) {
const input = document.querySelector(`input[data-row="${word.row}"][data-col="${word.col}"]`);
if (input) input.focus();
}
}
function selectCell(row, col) {
// Select the first word that uses this cell
const cell = grid[row][col];
if (cell.words.length) {
selectWord(cell.words[0]);
}
}
function handleInput(e, row, col) {
const val = e.target.value.toUpperCase();
if (!val.match(/^[A-Z]?$/)) {
e.target.value = '';
return;
}
grid[row][col].value = val;
checkWordsAtCell(row, col);
renderClues();
updateScore();
if (val) {
let word = null;
if (selectedWordId) {
word = WORDS.find(w => w.id === selectedWordId);
} else {
// Если слово не выбрано, выбираем первое из возможных для клетки
const cell = grid[row][col];
if (cell.words.length) {
word = WORDS.find(w => w.id === cell.words[0]);
selectedWordId = cell.words[0];
renderClues();
}
}
if (word) {
let nextRow = row;
let nextCol = col;
if (word.direction === 'across') nextCol++;
else nextRow++;
// Проверяем, есть ли следующая клетка в слове
for (let i = 0; i < word.word.length; i++) {
const r = word.row + (word.direction === 'down' ? i : 0);
const c = word.col + (word.direction === 'across' ? i : 0);
if (r === nextRow && c === nextCol) {
const nextInput = document.querySelector(`input[data-row="${nextRow}"][data-col="${nextCol}"]`);
if (nextInput) nextInput.focus();
break;
}
}
}
}
}
function checkWordsAtCell(row, col) {
const cell = grid[row][col];
cell.words.forEach(wordId => {
const word = WORDS.find(w => w.id === wordId);
let r = word.row, c = word.col, correct = true;
for (let i = 0; i < word.word.length; i++) {
if (grid[r][c].value !== word.word[i]) {
correct = false;
break;
}
if (word.direction === 'across') c++;
else r++;
}
if (correct) completedWords.add(wordId);
});
}
function updateScore() {
document.getElementById('scoreDisplay').textContent = `Words Completed: ${completedWords.size}`;
}
function resetCrossword() {
completedWords.clear();
selectedWordId = null;
createGrid();
renderGrid();
renderClues();
updateScore();
}
window.onload = () => {
createGrid();
renderGrid();
renderClues();
updateScore();
};
Код: Выделить всё
#scoreDisplay, #crosswordGrid, #acrossClues, #downClues {
background: whitesmoke;
border: thin dashed lightgray;
margin: 0.5rem;
padding: 0.5rem;
}
Подробнее здесь:
https://stackoverflow.com/questions/798 ... -next-cell
1764460802
Anonymous
[b]Проблема[/b] [list] [*]Когда я ввожу букву в ячейку, фокус [b]не перемещается[/b] на следующую ячейку в слове. [*]После ввода буквы вся система ввода перестает [b]отвечать[/b] — я не могу вводить больше букв, удалять их или нажимать на другие ячейки. [*]Ощущение, будто обработчик событий выдает ошибку и прекращает дальнейшее выполнение. [/list] Думаю, все проблемы в renderGrid(), но я не знаю, где именно они. (у меня все html-элементы написаны правильно) [code]const GRID_ROWS = 10; const GRID_COLS = 10; const WORDS = [ // Across { word: 'READ', clue: 'To look at and comprehend written words', row: 0, col: 0, direction: 'across', id: 1 }, { word: 'EASY', clue: 'Not difficult', row: 2, col: 2, direction: 'across', id: 2 }, { word: 'NOTE', clue: 'A short written message', row: 4, col: 4, direction: 'across', id: 3 }, { word: 'GAME', clue: 'An activity for fun or competition', row: 6, col: 6, direction: 'across', id: 4 }, // Down { word: 'RENT', clue: 'To pay for the use of something', row: 0, col: 0, direction: 'down', id: 5 }, { word: 'DEAN', clue: 'A college official', row: 0, col: 2, direction: 'down', id: 6 }, { word: 'SONG', clue: 'A musical composition', row: 2, col: 4, direction: 'down', id: 7 }, { word: 'MEGA', clue: 'Very large', row: 4, col: 6, direction: 'down', id: 8 }, ]; let grid = []; let selectedWordId = null; let completedWords = new Set(); function createGrid() { grid = Array.from({ length: GRID_ROWS }, (_, r) => Array.from({ length: GRID_COLS }, (_, c) => ({ row: r, col: c, letter: null, value: '', words: [] })) ); WORDS.forEach(wordObj => { let r = wordObj.row, c = wordObj.col; for (let i = 0; i < wordObj.word.length; i++) { const cell = grid[r][c]; cell.letter = wordObj.word[i]; cell.words.push(wordObj.id); if (wordObj.direction === 'across') c++; else r++; } }); } function renderGrid() { const table = document.getElementById('crosswordGrid'); table.innerHTML = ''; for (let r = 0; r < GRID_ROWS; r++) { const tr = document.createElement('tr'); for (let c = 0; c < GRID_COLS; c++) { const cell = grid[r][c]; const td = document.createElement('td'); if (cell.letter) { const input = document.createElement('input'); input.type = 'text'; input.maxLength = 1; input.className = 'crossword-cell'; input.value = cell.value; input.dataset.row = r; input.dataset.col = c; input.onfocus = () => selectCell(r, c); input.oninput = e => handleInput(e, r, c); td.appendChild(input); } else { td.className = 'cell-blocked'; } tr.appendChild(td); } table.appendChild(tr); } } function renderClues() { const acrossDiv = document.getElementById('acrossClues'); const downDiv = document.getElementById('downClues'); acrossDiv.innerHTML = ''; downDiv.innerHTML = ''; WORDS.forEach(word => { const clueDiv = document.createElement('div'); clueDiv.className = 'clue' + (selectedWordId === word.id ? ' selected' : '') + (completedWords.has(word.id) ? ' completed' : ''); clueDiv.textContent = word.clue; clueDiv.onclick = () => selectWord(word.id); if (word.direction === 'across') acrossDiv.appendChild(clueDiv); else downDiv.appendChild(clueDiv); }); } function selectWord(wordId) { selectedWordId = wordId; renderClues(); // Focus first cell of the word const word = WORDS.find(w => w.id === wordId); if (word) { const input = document.querySelector(`input[data-row="${word.row}"][data-col="${word.col}"]`); if (input) input.focus(); } } function selectCell(row, col) { // Select the first word that uses this cell const cell = grid[row][col]; if (cell.words.length) { selectWord(cell.words[0]); } } function handleInput(e, row, col) { const val = e.target.value.toUpperCase(); if (!val.match(/^[A-Z]?$/)) { e.target.value = ''; return; } grid[row][col].value = val; checkWordsAtCell(row, col); renderClues(); updateScore(); if (val) { let word = null; if (selectedWordId) { word = WORDS.find(w => w.id === selectedWordId); } else { // Если слово не выбрано, выбираем первое из возможных для клетки const cell = grid[row][col]; if (cell.words.length) { word = WORDS.find(w => w.id === cell.words[0]); selectedWordId = cell.words[0]; renderClues(); } } if (word) { let nextRow = row; let nextCol = col; if (word.direction === 'across') nextCol++; else nextRow++; // Проверяем, есть ли следующая клетка в слове for (let i = 0; i < word.word.length; i++) { const r = word.row + (word.direction === 'down' ? i : 0); const c = word.col + (word.direction === 'across' ? i : 0); if (r === nextRow && c === nextCol) { const nextInput = document.querySelector(`input[data-row="${nextRow}"][data-col="${nextCol}"]`); if (nextInput) nextInput.focus(); break; } } } } } function checkWordsAtCell(row, col) { const cell = grid[row][col]; cell.words.forEach(wordId => { const word = WORDS.find(w => w.id === wordId); let r = word.row, c = word.col, correct = true; for (let i = 0; i < word.word.length; i++) { if (grid[r][c].value !== word.word[i]) { correct = false; break; } if (word.direction === 'across') c++; else r++; } if (correct) completedWords.add(wordId); }); } function updateScore() { document.getElementById('scoreDisplay').textContent = `Words Completed: ${completedWords.size}`; } function resetCrossword() { completedWords.clear(); selectedWordId = null; createGrid(); renderGrid(); renderClues(); updateScore(); } window.onload = () => { createGrid(); renderGrid(); renderClues(); updateScore(); };[/code] [code]#scoreDisplay, #crosswordGrid, #acrossClues, #downClues { background: whitesmoke; border: thin dashed lightgray; margin: 0.5rem; padding: 0.5rem; }[/code] [code] [/code] Подробнее здесь: [url]https://stackoverflow.com/questions/79833594/javascript-crossword-input-freezes-and-focus-does-not-move-to-the-next-cell[/url]