使用CSS Grid Layout动态排列行中的元素时,浏览器会根据视口的大小计算连续的项目数。我正在寻找一种方法,使用JavaScript来确定给定视口大小的每一行中有多少项。我的目的是在最后填补不可避免的空行。
例如,给定下面列出的CSS和HTML,并且在特定视口大小时会产生以下布局:
在更宽的视口处产生这种布局:
每一个都在最后一行中缺少元素。
我正在寻找一种方法来确定一行中有多少元素。有了这些信息,我就可以动态加载更多的元素来填充最后一行,所以它与其余的相同。
CSS和HTML示例:
<style>
* {
box-sizing: border-box;
}
body {
padding: 1rem;
}
main {
max-width: 500px;
margin: 0 auto;
}
article {
margin: 1rem 0;
overflow: hidden;
}
main {
max-width: 10000px;
margin: 0;
}
article {
margin: 0;
}
.listings {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 1rem;
}
.listings {
font-family: Avenir, Roboto, Helvetica, san-serif;
font-size: 80%;
}
.listing {
display: flex;
flex-flow: column;
border: 1px solid silver;
}
.listing > h1 {
margin: 1rem 1rem 0;
}
.listing > div {
margin: 0.25em 1rem 1rem;
}
.listing > img {
width: auto;
max-height: 200px;
order: -1;
align-self: center;
}
</style>
&#13;
<main class="listings">
<article class="listing">
<img src="images/computer.jpg">
<h1>87,500</h1>
<div>1008[3/2]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>30,000</h1>
<div>952[2/1]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>70,000</h1>
<div>1090[3/1]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>11,000</h1>
<div>828[2/1]2</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>25,000</h1>
<div>1484[2/1]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>199,000</h1>
<div>2160[3/2]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>42,000</h1>
<div>1509[3/2]0</div>
</article>
<article class="listing">
<img src="images/computer.jpg">
<h1>230,000</h1>
<div>1885[3/2]0</div>
</article>
</main>
&#13;
答案 0 :(得分:3)
<强> elem.getBoundingClientRect().left
强>
elem.getBoundingClientRect().left
属性可用于获取CSS网格布局中的动态行数。只需遍历article
元素NodeList,然后将元素的getBoundingClientRect().left
值与之前的值进行比较。比较值将在每行内增加,然后在下一行开始时下降。计算增量直到第一次下降,以确定每行中的元素数。
var articles = document.querySelectorAll('article')
console.log(articles[0].getBoundingClientRect().left) // 16
console.log(articles[1].getBoundingClientRect().left) // 238.156
console.log(articles[2].getBoundingClientRect().left) // 460.312
console.log(articles[3].getBoundingClientRect().left) // 682.468
console.log(articles[4].getBoundingClientRect().left) // 904.625
console.log(articles[5].getBoundingClientRect().left) // 1126.78
console.log(articles[6].getBoundingClientRect().left) // 16
因此,我们只需计算上一个left
值与下一个值之间的值增加值,一旦下降,我们就会计算行数。
这里使用call
在NodeList上应用数组方法reduce
。使用reduce
结转每个值以与下一个值进行比较:
var rowlen = Array.prototype.reduce.call(document.querySelectorAll('article'), function (prev, next) {
if ( !prev[2] ) {
var ret = next.getBoundingClientRect().left
// if increasing, increment counter
if ( !(prev[0] > -1 && ret < prev[1]) ) { prev[0]++ }
else { prev[2] = 1 } // else stop counting
}
return [prev[0],ret, prev[2]] // [counter, elem, stop-counting]
}, [0,null,0])[0]
Codesandbox.io "complete partial row" example.
或者是老派的JS,在IIFE中嵌套for
循环:
var rowlen = (function () {
for ( var ii = 0, arts = document.querySelectorAll('article'),
len = arts.length, el = 0, ell = 0;
ii < len; ii++ ) {
el = arts[ii].getBoundingClientRect().left
if ( el > ell || 0 === ell ) { ell = el }
else { return ii; }
}
}())
答案 1 :(得分:0)
<强> elem.clientWidth
强>
此示例使用元素属性clientWidth
来计算每行中的元素数。
var rowlength = Math.floor( // round down to account for some spacing
document.body.clientWidth / // width of viewport divided by...
document.querySelectorAll('article')[0].clientWidth // width of an element
)
这给了我每行中的项目数,除了可能是最后一行。
完成最后一行
我知道我最初加载了8个元素,因此我现在可以计算完成最后一行所需的项目数量:
var numelementsloaded = 8
或者我可以计算加载元素的数量:
var numelementsloaded = document.querySelectorAll('article').length
modulus(除法余数)运算符会给出最后一行中元素的数量:
var numelementslastrow = elementsloaded % rowlength
现在计算完成最后一行所需的元素数量:
var numelementsneeded = rowlength - numelementslastrow
全部一起压缩,并带有奖励:
var rowlength = Math.floor(document.body.clientWidth/document.querySelectorAll('article')[0].clientWidth)
var numelementsneeded = rowlength - (document.querySelectorAll('article').length % rowlength)
// and duplicating the first few elements to illustrate completing the last row
for ( var ii = 0; ii < numelementsneeded; ii++ ) {
document.querySelector('main').appendChild(
// here is where I'd pull in new items from the server
document.querySelectorAll('article')[ii].cloneNode(true)
)
}
这就完成了最后一行:
Codesandbox.io "complete last row" example.
删除最后一行
另一个技术上更简单的选择是 - 而不是添加新项目 - 删除最后一个部分行中的所有项目:
var rowlength = Math.floor(document.body.clientWidth/document.querySelectorAll('article')[0].clientWidth)
var numelementslastrow = document.querySelectorAll('article').length % rowlength
// and dropping the elements in the last row
for ( var ii = 0; ii < numelementslastrow; ii++ ) {
document.querySelector('main').removeChild(
document.querySelector('article:last-child')
)
}
如果最后一行已满,则会保留。例如,如果有8个项目,每行有4个项目,则8 mod 4 = 0,因此for
循环不会执行。