JavaScript para alterar a cor de fundo da célula da grade ao clicar
Tenho HTML básico conforme abaixo:
<!DOCTYPE html>
<html>
<head>
<title>Art Maker!</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Monoton">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Pixel Art</h1>
<h2>Choose Grid Size</h2>
<form id="sizePicker">
Grid Height:
<input type="number" id="inputHeight" name="height" min="1" value="1">
Grid Width:
<input type="number" id="inputWidth" name="width" min="1" value="1">
<input type="submit">
</form>
<h2>Pick A Color</h2>
<input type="color" id="colorPicker">
<h2>Design Canvas</h2>
<table id="pixelCanvas"></table>
<script src="designs.js"></script>
</body>
</html>
Os JavaScript abaixo são usados para:
- obter a entrada do usuário: altura e largura
- desenhar grade com base na altura e largura
- obter seletor de cores HTML
- preencher uma célula com a cor de fundo com base na etapa (3) quando o usuário clicar na célula
Estou preso na etapa (4). Criei uma função respondToClick (event) e anexei a tblRow com eventListener. Deve preencher a célula com a cor de fundo ao "clicar"; mas isso não acontece. Por favor, avise onde está errado.
// obtém o valor do tamanho da grade; altura largura
let height = document.getElementById('inputHeight').value;
let width = document.getElementById('inputWidth').value;
const gridHeight = document.getElementById('inputHeight');
gridHeight.addEventListener("input", function() {
height = document.getElementById('inputHeight').value;
})
const gridWidth = document.getElementById('inputWidth');
gridWidth.addEventListener("input", function() {
width = document.getElementById('inputWidth').value;
})
/ função para criar tela
const table = document.getElementById('pixelCanvas');
function createCanvas(event) {
for (let h = 1; h <= height; h++) {
const row = document.createElement('tr');
for (let w = 1; w <= width; w++) {
const cell = document.createElement('td');
cell.style.cssText = "height: 15px; width: 15px";
row.appendChild(cell);
}
table.appendChild(row);
}
}
const form = document.querySelector('form');
// vincula createCanvas () a "submit"
form.addEventListener('submit', createCanvas);
// ouvinte de evento para atualizar a cor
let color = document.getElementById('colorPicker').value;
document.getElementById('colorPicker').onchange = function() {
color = this.value;
}
// função ativada quando o usuário clica apenas em
function respondToClick(event) {
if (event.target.nodeName.toLowerCase() === 'td') {
event.target.style.backgroundColor = color;
}
}
const tblRow = document.getElementsByTagName('tr');
tblRow.forEach(row => function() {
row.addEventListener("click", respondToClick);
});
Respostas
A seguir estão os problemas em seu código:
document.getElementsByTagName(...)retorna um HTMLCollectionno qual você não pode chamar o.forEach()método. Em vez disso, usedocument.querySelectorAll(...)which retorna a NodeListque tem um método chamado.forEach().const tblRow = document.querySelectorAll('tr');Você precisa evitar o comportamento padrão do
submitevento usandoEvent.preventDefault()function createCanvas(event) { event.preventDefault(); ... }Como você chamou o
.forEach()método no HTMLCollectionretornado pordocument.getElementsByTagName('tr'), ocorreu um erro e nenhum ouvinte de evento foi adicionado a qualquertrelemento.Em vez de adicionar
clickouvinte de evento em cadatrelemento, você pode aproveitarEvent Bubblinge apenas adicionar o ouvinte de evento aotableelemento.table.addEventListener("click", respondToClick);
O snippet de código a seguir mostra o exemplo de código fixo:
let height = document.getElementById('inputHeight').value;
let width = document.getElementById('inputWidth').value;
const gridHeight = document.getElementById('inputHeight');
const gridWidth = document.getElementById('inputWidth');
const table = document.getElementById('pixelCanvas');
const form = document.querySelector('form');
const colorPicker = document.getElementById('colorPicker');
let color = colorPicker.value;
gridHeight.addEventListener("input", function() {
height = document.getElementById('inputHeight').value;
})
gridWidth.addEventListener("input", function() {
width = document.getElementById('inputWidth').value;
})
function createCanvas(event) {
event.preventDefault();
for (let h = 1; h <= height; h++) {
const row = document.createElement('tr');
for (let w = 1; w <= width; w++) {
const cell = document.createElement('td');
row.appendChild(cell);
}
table.appendChild(row);
}
}
form.addEventListener('submit', createCanvas);
colorPicker.addEventListener('change', function() {
color = this.value;
});
function respondToClick(event) {
if (event.target.matches('td')) {
event.target.style.backgroundColor = color;
}
}
table.addEventListener("click", respondToClick);
table,
tr,
td {
border: 1px solid;
border-collapse: collapse;
;
}
td {
width: 30px;
height: 30px;
}
<h1>Pixel Art</h1>
<h2>Choose Grid Size</h2>
<form id="sizePicker">
Grid Height:
<input type="number" id="inputHeight" name="height" min="1" value="1" /> Grid Width:
<input type="number" id="inputWidth" name="width" min="1" value="1" />
<input type="submit" />
</form>
<h2>Pick A Color</h2>
<input type="color" id="colorPicker" />
<h2>Design Canvas</h2>
<table id="pixelCanvas"></table>
Observação lateral: dentro do responseToClick()manipulador de eventos, você tem a seguinte linha de código:
cell.style.cssText = "height: 15px; width: 15px";
Embora isso funcione, é melhor definir esses estilos no CSS. Eu fiz o mesmo no trecho de código acima.
Outro ponto que deve ser observado é que, após corrigir o código conforme mostrado no trecho de código acima, você pode querer remover o conteúdo da tabela criado anteriormente antes de criar um novo. Se é isso que você deseja fazer, você pode fazer isso definindo o .innerHTMLdo tableelemento como uma string vazia dentro do createCanvas()manipulador de eventos.
alguns problemas
- você deve vincular o manipulador de cliques após criar o,
rowspois vinculou otr. Ou melhor ainda, como você já delega o evento, use o elemento table para vincular o manipulador, pois ele está lá desde o início. - você precisa impedir o envio do formulário ( causa um recarregamento da página )
- você precisa limpar a tela ao criar um novo
// obtain grid size value; height & width
const gridHeight = document.getElementById('inputHeight');
const gridWidth = document.getElementById('inputWidth');
let height = gridHeight.value;
let width = gridWidth.value;
gridHeight.addEventListener("input", function() {
height = document.getElementById('inputHeight').value;
})
gridWidth.addEventListener("input", function() {
width = document.getElementById('inputWidth').value;
})
const table = document.getElementById('pixelCanvas');
function createCanvas(event) {
event.preventDefault();
table.innerHTML = '';
for (let h = 1; h <= height; h++) {
const row = document.createElement('tr');
for (let w = 1; w <= width; w++) {
const cell = document.createElement('td');
row.appendChild(cell);
}
table.appendChild(row);
}
}
const form = document.querySelector('form');
// bind createCanvas() to "submit"
form.addEventListener('submit', createCanvas);
// event listener to update color
const picker = document.getElementById('colorPicker')
let color = picker.value;
picker.onchange = function() {
color = this.value;
}
// function activated when user click on only
function respondToClick(event) {
if (event.target.nodeName.toLowerCase() === 'td') {
event.target.style.backgroundColor = color;
}
}
table.addEventListener("click", respondToClick);
table {
border: 1px solid black;
}
td{
width:15px;
height:15px;
overflow:hidden;
}
<h1>Pixel Art</h1>
<h2>Choose Grid Size</h2>
<form id="sizePicker">
Grid Height:
<input type="number" id="inputHeight" name="height" min="1" value="1"> Grid Width:
<input type="number" id="inputWidth" name="width" min="1" value="1">
<input type="submit">
</form>
<h2>Pick A Color</h2>
<input type="color" id="colorPicker">
<h2>Design Canvas</h2>
<table id="pixelCanvas" cellspacing="0" cellpadding="0"></table>