问题
What I wanna do is to make a CSS grid with a dynamic number of cells. For the sake of simplicity, let's assume there will always be four cells per row. Can I specify a grid with such a dynamic number of rows?
To make it easier, here's the Flexbox implementation:
const COLORS = [
'#FE9',
'#9AF',
'#F9A',
"#AFA",
"#FA7"
];
function addItem(container, template) {
let color = COLORS[_.random(COLORS.length - 1)];
let num = _.random(10000);
container.append(Mustache.render(template, { color, num }));
}
$(() => {
const tmpl = $('#item_template').html()
const container = $('#app');
for(let i=0; i<5; i++) { addItem(container, tmpl); }
$('#add_el').click(() => {
addItem(container, tmpl);
})
container.on('click', '.del_el', (e) => {
$(e.target).closest('.item').remove();
});
});
.container {
width: 100%;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.container .item {
flex: 0 0 calc(25% - 1em);
min-height: 120px;
margin: 0.25em 0.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app" class="container">
</div>
<button id="add_el">Add element</button>
<template id="item_template">
<div class="item" style="background: {{color}}">
<p>{{ num }}</p>
<p>
<button class="del_el">Delete</button>
</p>
</div>
</template>
P.S. Apparently, I wasn't clear enough the first time... I want to recreate this effect using the latest CSS Grid Layout.
回答1:
Okay, after reading the MDN reference, I found the answer! The key to dynamic rows (or columns) is the repeat property.
const COLORS = [
'#FE9',
'#9AF',
'#F9A',
"#AFA",
"#FA7"
];
function addItem(container, template) {
let color = COLORS[_.random(COLORS.length - 1)];
let num = _.random(10000);
container.append(Mustache.render(template, { color, num }));
}
$(() => {
const tmpl = $('#item_template').html()
const container = $('#app');
for(let i=0; i<5; i++) { addItem(container, tmpl); }
$('#add_el').click(() => {
addItem(container, tmpl);
})
container.on('click', '.del_el', (e) => {
$(e.target).closest('.item').remove();
});
});
.container {
width: 100%;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(auto-fill, 120px);
grid-row-gap: .5em;
grid-column-gap: 1em;
}
.container .item {
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app" class="container">
</div>
<button id="add_el">Add element</button>
<template id="item_template">
<div class="item" style="background: {{color}}">
<p>{{ num }}</p>
<p>
<button class="del_el">Delete</button>
</p>
</div>
</template>
P.S. Or you can use grid-auto-rows in my particular example.
回答2:
Something like this?
$(document).ready(function() {
//Prepare Element selectors
var cssElem = $("#Dynam"), rowElem = $("#rows"), columnElem = $("#columns"), appElem = $("#app");
var noItems = $(".item").length,defaultColumns = 4;
//Init default state
cssElem.html(".container .item {flex: 0 0 calc(" + (100 / defaultColumns) + "% - 1em);}");
columnElem.val(defaultColumns);
rowElem.val(Math.ceil(noItems / columnElem.val()));
//Add listeners to change
appElem.on("DOMSubtreeModified", function() {
noItems = $(".item").length;
rowElem.val(Math.ceil(noItems / columnElem.val()));
});
columnElem.on("change", function() {
rowElem.val(Math.ceil(noItems / columnElem.val()));
cssElem.html(".container .item {flex: 0 0 calc(" + (100 / columnElem.val()) + "% - 1em);}");
});
rowElem.on("change", function() {
columnElem.val(Math.ceil(noItems / rowElem.val()));
cssElem.html(".container .item {flex: 0 0 calc(" + (100 / columnElem.val()) + "% - 1em);}");
});
});
const COLORS = ['#FE9', '#9AF', '#F9A', "#AFA", "#FA7"];
function addItem(container, template) {
let color = COLORS[_.random(COLORS.length - 1)];
let num = _.random(10000);
container.append(Mustache.render(template, {
color,
num
}));
}
$(() => {
const tmpl = $('#item_template').html()
const container = $('#app');
for (let i = 0; i < 5; i++) {
addItem(container, tmpl);
}
$('#add_el').click(() => {
addItem(container, tmpl);
})
container.on('click', '.del_el', (e) => {
$(e.target).closest('.item').remove();
});
});
.container {
width: 100%;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.container .item {
min-height: 120px;
margin: 0.25em 0.5em;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style id="Dynam"></style>
<button id="add_el">Add element</button> rows:
<input id="rows" /> columns:<input id="columns" />
<div id="app" class="container">
</div>
<template id="item_template">
<div class="item" style="background: {{color}}">
<p>{{ num }}</p>
<p>
<button class="del_el">Delete</button>
</p>
</div>
</template>
回答3:
You don't need to use repeat. Instead you can just use set a variable --grid-template-columns from your javascript code.
rootEl.style.setProperty('--grid-template-columns' theGridTemplateColumnsValue)
theGridTemplateColumnsValue is a string that can also contains other css variables. This way you can have a dynamic number of columns per row.
回答4:
Another option is to use JavaScript to set the gridTemplateRows and the gridTemplateColumns attributes dynamically. This can be done as follows:
function initDynamicGrid(numRows, numColumns){
const totalSqaures = numRows * numColumns;
let rowsString = "";
let columnsString = "";
for(let i = 0; i < numRows;i++){
if(i === numRows -1){
rowsString +="1fr";
}else{
rowsString +="1fr ";
}
}
for(let i = 0; i < numColumns;i++){
if(i === numColumns -1){
columnsString +="1fr";
}else{
columnsString +="1fr ";
}
}
let gridContainer = document.createElement('div');
gridContainer.style.display ="grid";
gridContainer.style.gridTemplateRows = rowsString;
gridContainer.style.gridTemplateColumns = columnsString;
for(let i = 0; i < totalSqaures; i++){
let squareInGrid = document.createElement('div');
// Here you can put stuff into the squareInGrid or append css to it.
gridContainer.appendChild(squareInGrid );
}
}
It might not be too fancy but its a nice and simple way to get the job done. I hope this helped somebody.
来源:https://stackoverflow.com/questions/43115822/can-i-emulate-css-grids-with-dynamic-number-of-cells-rows-in-javascript