欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

js+CSS簡單實(shí)現(xiàn)瀑布流布局

 更新時(shí)間:2023年11月21日 10:59:18   作者:sherlockkid7  
瀑布流布局,是一種視覺表現(xiàn)為參差不齊的多欄布局,常用于內(nèi)容以圖片為主的頁面展示,本文將使用css和js兩種方式來實(shí)現(xiàn)瀑布流布局,需要的可以參考下

前言

瀑布流布局,是一種視覺表現(xiàn)為參差不齊的多欄布局。常用于內(nèi)容以圖片為主的頁面展示,圖片等寬不等高,每行從左到右排滿后,后面的元素依次添加至短的一列其后。隨著頁面向下滾動(dòng),還會(huì)不斷加載數(shù)據(jù)并添加到當(dāng)前尾部,視覺上顯得錯(cuò)落有致不拘一格。今天使用css和js兩種方式來實(shí)現(xiàn)瀑布流布局

css實(shí)現(xiàn)瀑布流布局

該方式實(shí)現(xiàn)的瀑布流布局其中的內(nèi)容數(shù)據(jù)是固定的,主要利用了 CSS 的多列屬性 columns

頁面結(jié)構(gòu):創(chuàng)建容器container,該容器包裹所有用于展示的元素item(圖片和標(biāo)題)

  <div class="container">
    <div class="item">
      <img src="..."/>
      <h2>...</h2>
    </div>
    ...
</div>

給容器container設(shè)置寬度,并居中顯示;控制其中的內(nèi)容分成3列columns: 3;,列與列之間的距離為20pxcolumn-gap: 20px;

每個(gè)item元素,設(shè)置屬性break-inside: avoid;, 避免在多列布局中元素內(nèi)容被分割(元素的內(nèi)容被自動(dòng)斷開,圖片在一列尾部,文字在下一列的頭部)

.container {
  width: 1200px;
  margin: 20px auto;
  columns: 3;
  column-gap: 20px;
}

.container .item {
  width: 100%;
  break-inside: avoid;
  margin-bottom: 20px;
}
.container .item img{
  width: 100%;
}

小結(jié):根據(jù)上圖可以看出CSS的多列布局實(shí)現(xiàn)的瀑布流是從上到下,再從左到右的順序排列元素,適用于對(duì)于元素順序沒有要求,且元素?cái)?shù)據(jù)固定的情況

js實(shí)現(xiàn)瀑布流布局

思路:

每個(gè)元素使用絕對(duì)定位的方式,動(dòng)態(tài)的設(shè)置相應(yīng)的top,left值進(jìn)行排列,先計(jì)算一行能夠容納幾列元素,第一行元素直接設(shè)置top為0,left為索引乘以(元素寬度 + 間隙)進(jìn)行排列,后面的元素排列,需要找出所有列中高度最小的那一列,將元素添加至高度最小的那一列后面,直至所有元素添加完畢。

創(chuàng)建一個(gè)容器container,用于存放展示的元素。并設(shè)置css為相對(duì)定位,其中展示的元素為絕對(duì)定位

<div id="container"></div>

計(jì)算頁面一行能容納幾列元素

列數(shù) = 頁面的寬度 / (元素的寬度+元素之間的間隙 ) column = pageWidth / (itemWidth + gap);

注:頁面的寬度這里設(shè)置的是body的寬度(使用css控制了最大寬度和最小寬度)

創(chuàng)建createElement函數(shù),用來動(dòng)態(tài)創(chuàng)建組成瀑布流的元素塊(包含圖片和標(biāo)題),并在請(qǐng)求數(shù)據(jù)成功后調(diào)用添加到頁面中,并進(jìn)行瀑布流布局

function createElement(itemData) {
  return new Promise((resolve, reject) => {
    let div = document.createElement('div')
    div.innerHTML = `...`
    div.className = 'item'
    // 監(jiān)聽圖片的load事件
    div.querySelector('img').addEventListener('load', () => {
      resolve(div)
    })
  })
}

// 獲取喵咪的數(shù)據(jù)
let page = 1  //請(qǐng)求數(shù)據(jù)的頁碼
let isReq = false  //設(shè)置節(jié)流閥,處于請(qǐng)求過程中,則不再請(qǐng)求數(shù)據(jù)
function loadNewData() {
  if (isReq) return
  isReq = true
  getData()
    .then(data => {
      // 處理新的數(shù)據(jù)
      let items = data
      let promises = items.map(item => createElement(item))
      Promise.all(promises).then(nodes => {
        let frag = document.createDocumentFragment()
        isReq = false
        page++
        nodes.forEach(node => {
          frag.appendChild(node)
          Node.push(node)
        })
        document.getElementById('container').appendChild(frag)
        waterfall(Node)
      })
    })
    
}

注:遇到獲取元素塊高度不正確的問題

因?yàn)閳D片可能還沒有完全加載,獲取的元素塊高度就只是h4標(biāo)簽的高度。因此需要在圖片加載完成后再獲取元素的高度。

a.通過監(jiān)聽圖片的 load 事件,當(dāng)事件觸發(fā)時(shí),表示圖片已經(jīng)加載完成,返回創(chuàng)建的div元素

b.在獲取數(shù)據(jù)loadNewData()函數(shù)中,對(duì)返回的數(shù)據(jù)執(zhí)行創(chuàng)建元素方法,并使用Promise.all()對(duì)由返回的div元素(Promise 實(shí)例)組成的Promise 數(shù)組進(jìn)行處理,當(dāng)每個(gè)Promise實(shí)例的狀態(tài)變?yōu)?fulfilled(所有圖片都加載完成),就執(zhí)行瀑布流布局

創(chuàng)建waterfall函數(shù),實(shí)現(xiàn)瀑布流

接收元素?cái)?shù)組,然后對(duì)每個(gè)元素進(jìn)行布局。如果元素在第一行,那么它的頂部位置就是 0,左側(cè)位置就是它的索引乘以(元素寬度 + 間隙)。如果元素不在第一行,那么我們首先找出高度最小的列,然后將元素放在這個(gè)列的下方,并更新這個(gè)列的高度。

function waterfall(items) {
  for (var i = loaded; i < items.length; i++) {
    let item = items[i]
    let height = item.offsetHeight
    if (i < columns) {
      //滿足這個(gè)條件則說明在第一行
      item.style.top = 0
      item.style.left = (itemWidth + gap) * i + 'px'
      heightArr.push(height)
    } else {
      //其他行,先找出最小高度列的索引
      const minIndex = getMinIndex(heightArr)
      //top值就是最小列的高度+gap
      const top = heightArr[minIndex] + gap
      item.style.top = top + 'px'
      item.style.left = minIndex * (itemWidth + gap) + 'px'

      //修改原本最小列的高度 
      heightArr[minIndex] = top + height
    }
    loaded = items.length
  }
}

//用于獲取heightArr數(shù)組中值最小的列的索引。
const getMinIndex = (array) => {
  const min = Math.min.apply(null, array)
  return array.indexOf(min)
}

監(jiān)聽頁面滾動(dòng),當(dāng)未顯示的元素內(nèi)容小于屏幕高度的一大半(這里設(shè)置的0.7,因?yàn)閿?shù)據(jù)加載比較慢,一般設(shè)置成0.5就可以),就需要加載新數(shù)據(jù)進(jìn)行展示

window.addEventListener('scroll', lazy)
function lazy() {
 const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
 const documentHeight = document.documentElement.scrollHeight
  // 未顯示的內(nèi)容 = 文檔(內(nèi)容)高度-滾動(dòng)高度-屏幕高度
  if (documentHeight - scrollTop - clientHeight < 0.7 * clientHeight) {
    loadNewData()
  }
}

小結(jié):

a. 簡單封裝的請(qǐng)求數(shù)據(jù)方法getData()沒有展示出來,請(qǐng)求的接口是從網(wǎng)上找的(地址),一次只能加載10張,并且加載很慢,可以自行查找接口。

b. 需要定義的變量

根據(jù)以上基本可以實(shí)現(xiàn)瀑布流了,排列順序和滾動(dòng)頁面加載數(shù)據(jù)也比較符合一般情況

以上就是js+CSS簡單實(shí)現(xiàn)瀑布流布局的詳細(xì)內(nèi)容,更多關(guān)于js瀑布流布局的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論