简体   繁体   中英

Generate cells for CSS grid via JavaScript

I'm trying to generate grid cells dynamically, but in a specific pattern. I copied a lot of <div> s, made the necessary adjustments by hand, and got the results I needed, but I'm wondering if someone can help me in developing an algorithm for producing it automatically. If you look at the example below, the left box is what I want to dynamically calculate.

 function calcCells(){ let cells = ''; for(let a = 1; a <= 10; a++){ for(let b = 1; b <= a; b++){ cells += `<div style="background:#fd8362; grid-area: ${a % b} / ${a % b} / ${a % b} / ${a % b}"> ${b} </div>` } } return cells; } document.getElementById("grid-body-algorithm").innerHTML = calcCells();
 #grid-body, #grid-body-algorithm { float:left; margin-right:30px; box-shadow: 0 0 10px rgba(0, 0, 0, .2); text-align: center; display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(5, 1fr); justify-content: center; align-content: end; border-radius: 5px; width:150px; height:150px; color:#444444; padding:1px; } #grid-body > *, #grid-body-algorithm > *{ border:1px solid white; }
 <div id="grid-body"> <div style="background:#fd8362; grid-area: 1 / 1 / 1 / 1">1</div> <div style="background:#ffad97; grid-area: 2 / 1 / 2 / 1">1</div> <div style="background:#ffad97; grid-area: 1 / 2 / 1 / 2">2</div> <div style="background:#ffded6; grid-area: 3 / 1 / 3 / 1">1</div> <div style="background:#ffded6; grid-area: 2 / 2 / 2 / 2">2</div> <div style="background:#ffded6; grid-area: 1 / 3 / 1 / 3">3</div> <div style="background:#fff0ec; grid-area: 4 / 1 / 4 / 1">1</div> <div style="background:#fff0ec; grid-area: 3 / 2 / 3 / 2">2</div> <div style="background:#fff0ec; grid-area: 2 / 3 / 2 / 3">3</div> <div style="background:#fff0ec; grid-area: 1 / 4 / 2 / 4">4</div> </div> <div id="grid-body-algorithm"> </div>

From the desired output, we can see that the taxicab distance from the top-left corner determines the desired color, and the column number determines the cell text.

The inner loop should be constrained to stay within a maximum taxicab distance. This maximum could be a parameter to your function. In your example that maximum is 3 (as the furthest cells that are concerned are 3 taxicab steps away from the top-left cell).

Furthermore, the desired color seems to get lighter the greater that taxicab distance is. For that we could vary the alpha part of the same, fixed background color. In RGBA notation, this alpha component which can have a value between 0 and 1.

I opted for creating a document fragment instead of HTML. That way the setting of cell attributes is more JS-syntax controlled and more object oriented.

I didn't touch your CSS.

In this implementation I added an input box with which you can control the maximum taxicab distance that will be used:

 function calcCells(maxDistance) { const fragment = document.createDocumentFragment(); for (let row = 1; row <= 5; row++) { // row + col - 2 is taxicab distance from top-left corner for (let col = 1, distance = row - 1; distance <= maxDistance && col <= 5; col++, distance++) { const cell = document.createElement("div"); // Set background transparency with the alpha part of the background color cell.style.background = `rgba(240,120,80,${1 - (distance + 0.5) / (maxDistance + 1)})`; cell.style.gridArea = [row, col, row, col].join(" / "); cell.textContent = col; fragment.appendChild(cell); } } return fragment; } const inputDistance = document.querySelector("input"); const outputGrid = document.getElementById("grid-body-algorithm"); function refresh() { const maxDistance = +inputDistance.value; outputGrid.innerHTML = ""; // clear previous content outputGrid.appendChild(calcCells(maxDistance)); } inputDistance.addEventListener("click", refresh); refresh();
 #grid-body, #grid-body-algorithm { float:left; margin-right:30px; box-shadow: 0 0 10px rgba(0, 0, 0, .2); text-align: center; display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(5, 1fr); justify-content: center; align-content: end; border-radius: 5px; width:150px; height:150px; color:#444444; padding:1px; } #grid-body > *, #grid-body-algorithm > *{ border:1px solid white; }
 <div id="grid-body-algorithm"></div> distance: <input type="number" value="3" min="0" max="8">

First of all, you should use an eventListener or the defer -attribute to wait until the DOM structure is loaded and the element exists.

Then you should not use innerHTML to create elements. It is slow as the DOM needs to be reparsed and is an XSS-Injection vulnerability.

To create Elements use either the appendChild or the insertAdjacentHTML method.

Instead of adding everything as inline-style I would work with CSS which is cleaner and with the use of SASS even shorter.

As you already figured out, you need 2 variables. One for the row and one for the column. The first for -loop needs the one for the rows and the 2nd for the columns:

 window.addEventListener('DOMContentLoaded', function() { for (let i = 1, n = 5; i < 5; i++) { for (let j = 1; j < n; j++) { document.querySelector('#grid-body-algorithm').insertAdjacentHTML('beforeend', ` <div data-row="${i}" data-col="${j}">${j}</div>` ); } n--; } })
 #grid-body-algorithm { width: 150px; height: 150px; display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(5, 1fr); padding: 2px; gap: 2px; border: 1px solid black; } [data-row="1"] { grid-row: 1 / 2; } [data-row="2"] { grid-row: 2 / 3; } [data-row="3"] { grid-row: 3 / 4; } [data-row="4"] { grid-row: 4 / 5; } [data-row="5"] { grid-row: 5 / 6; } [data-row="1"][data-col="1"] { background: #fd8362; } [data-row="1"][data-col="2"], [data-row="2"][data-col="1"] { background: #ffad97; } [data-row="1"][data-col="3"], [data-row="2"][data-col="2"], [data-row="3"][data-col="1"] { background: #ffded6; } [data-row="1"][data-col="4"], [data-row="2"][data-col="3"], [data-row="3"][data-col="2"], [data-row="4"][data-col="1"] { background: #fff0ec; }
 <div id="grid-body-algorithm"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM