css 统计动态行中有多少个元素

sg24os4d  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(123)

当使用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>

个字符

5vf7fwbs

5vf7fwbs1#

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值和下一个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; }
  }
}())


Codesandbox.io "drop partial row" example.

7gyucuyw

7gyucuyw2#

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循环不会执行。
Codesandbox.io "drop partial row" example.

相关问题