最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3實(shí)現(xiàn)瀑布流的2種核心方案

 更新時(shí)間:2025年12月02日 08:49:23   作者:北極糊的狐  
這篇文章主要介紹了Vue3中實(shí)現(xiàn)瀑布流的兩種主要方案:CSS原生方案和JS計(jì)算方案,CSS方案適用于靜態(tài)短列表,而JS方案適用于長(zhǎng)列表和復(fù)雜布局,能夠保證排序正常并支持懶加載,文章詳細(xì)介紹了兩種方案的實(shí)現(xiàn)步驟,需要的朋友可以參考下

查資料Vue3 中實(shí)現(xiàn)瀑布流主要有 CSS 原生方案(簡(jiǎn)單場(chǎng)景) 和 JS 計(jì)算方案(復(fù)雜場(chǎng)景),整理了兩種方法的實(shí)現(xiàn)步驟。

一、方案對(duì)比

方案核心原理優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景
CSS 方案column-count/grid 布局代碼簡(jiǎn)單、無(wú) JS 計(jì)算排序亂(按列排布)、不支持懶加載靜態(tài)短列表、簡(jiǎn)單瀑布流
JS 方案計(jì)算列高 + 動(dòng)態(tài)插入排序正常、支持懶加載需 JS 計(jì)算、適配窗口變化動(dòng)態(tài)加載、長(zhǎng)列表、復(fù)雜布局

二、方案 1:CSS 原生實(shí)現(xiàn)(快速上手)

1. column 多列布局(最簡(jiǎn)單)

利用 column-count 拆分列,column-gap 控制列間距,適合靜態(tài)數(shù)據(jù)展示。

<template>
  <div class="waterfall-css">
    <div 
      class="waterfall-item" 
      v-for="(item, index) in list" 
      :key="index"
    >
      <img :src="item.img" alt="瀑布流圖片" class="item-img" />
      <p class="item-desc">{{ item.desc }}</p>
    </div>
  </div>
</template>
 
<script setup>
import { ref } from 'vue';
 
// 模擬瀑布流數(shù)據(jù)
const list = ref([
  { img: 'https://picsum.photos/300/400?1', desc: '圖片1' },
  { img: 'https://picsum.photos/300/300?2', desc: '圖片2' },
  { img: 'https://picsum.photos/300/500?3', desc: '圖片3' },
  { img: 'https://picsum.photos/300/200?4', desc: '圖片4' },
  { img: 'https://picsum.photos/300/600?5', desc: '圖片5' },
  { img: 'https://picsum.photos/300/350?6', desc: '圖片6' },
]);
</script>
 
<style scoped>
/* 瀑布流容器 */
.waterfall-css {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  /* 核心:拆分為3列 */
  column-count: 3;
  /* 列間距 */
  column-gap: 16px;
  padding: 16px;
}
 
/* 瀑布流項(xiàng)(避免跨列斷裂) */
.waterfall-item {
  /* 關(guān)鍵:禁止跨列 */
  break-inside: avoid;
  margin-bottom: 16px;
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  overflow: hidden;
}
 
/* 圖片自適應(yīng) */
.item-img {
  width: 100%;
  height: auto;
  display: block;
}
 
.item-desc {
  padding: 12px;
  font-size: 14px;
  color: #333;
}
 
/* 響應(yīng)式適配 */
@media (max-width: 768px) {
  .waterfall-css {
    column-count: 2; /* 移動(dòng)端2列 */
  }
}
@media (max-width: 480px) {
  .waterfall-css {
    column-count: 1; /* 小屏1列 */
  }
}
</style>

2. CSS Grid 布局(更靈活)

適合需要自定義列寬、對(duì)齊方式的場(chǎng)景,兼容現(xiàn)代瀏覽器。

<template>
  <div class="waterfall-grid">
    <div 
      class="waterfall-item" 
      v-for="(item, index) in list" 
      :key="index"
    >
      <img :src="item.img" alt="" class="item-img" />
    </div>
  </div>
</template>
 
<script setup>
import { ref } from 'vue';
const list = ref([/* 同上文數(shù)據(jù) */]);
</script>
 
<style scoped>
.waterfall-grid {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px;
  /* Grid 核心配置 */
  display: grid;
  /* 3列,列寬自適應(yīng),間距16px */
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 16px;
  /* 行高自適應(yīng)(關(guān)鍵) */
  grid-auto-rows: minmax(100px, auto);
}
 
.waterfall-item {
  border-radius: 8px;
  overflow: hidden;
}
 
.item-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
 
/* 響應(yīng)式 */
@media (max-width: 768px) {
  .waterfall-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
</style>

三、方案 2:JS 計(jì)算實(shí)現(xiàn)(推薦,排序正常)

CSS 方案的缺陷是「元素按列從上到下排布」(而非從左到右),JS 方案通過(guò)計(jì)算每列高度,將新元素插入最短列,保證排序和布局更符合預(yù)期。

完整實(shí)現(xiàn)(含懶加載 + 窗口適配)

<template>
  <div class="waterfall-js" ref="waterfallRef">
    <!-- 列容器(動(dòng)態(tài)生成) -->
    <div 
      class="waterfall-column" 
      v-for="(col, index) in columnList" 
      :key="index"
      ref="columnRefs"
    >
      <!-- 列內(nèi)元素 -->
      <div 
        class="waterfall-item" 
        v-for="item in col" 
        :key="item.id"
        @load="handleImgLoad(item.id)"
      >
        <img 
          :src="item.img" 
          alt="" 
          class="item-img"
          :data-id="item.id"
          loading="lazy" <!-- 原生懶加載 -->
        />
        <p class="item-desc">{{ item.desc }}</p>
      </div>
    </div>
    <!-- 加載更多 -->
    <div class="load-more" v-if="hasMore" @click="loadMore">加載更多</div>
    <div class="no-more" v-else>沒(méi)有更多數(shù)據(jù)了</div>
  </div>
</template>
 
<script setup>
import { ref, onMounted, onResize, nextTick } from 'vue';
 
// 核心變量
const waterfallRef = ref(null); // 瀑布流容器
const columnRefs = ref([]); // 列容器引用
const columnCount = ref(3); // 列數(shù)(默認(rèn)3列)
const columnHeights = ref([]); // 每列的高度
const columnList = ref([]); // 每列的元素列表
const hasMore = ref(true); // 是否有更多數(shù)據(jù)
let page = 1; // 當(dāng)前頁(yè)碼
 
// 初始化列
const initColumns = () => {
  // 根據(jù)屏幕寬度設(shè)置列數(shù)
  const width = document.documentElement.clientWidth;
  if (width <= 480) {
    columnCount.value = 1;
  } else if (width <= 768) {
    columnCount.value = 2;
  } else {
    columnCount.value = 3;
  }
  // 重置列數(shù)據(jù)
  columnList.value = Array.from({ length: columnCount.value }, () => []);
  columnHeights.value = Array(columnCount.value).fill(0);
};
 
// 模擬請(qǐng)求數(shù)據(jù)
const fetchData = async (pageNum) => {
  // 模擬接口延遲
  await new Promise(resolve => setTimeout(resolve, 500));
  const mockData = Array.from({ length: 9 }, (_, i) => ({
    id: `${pageNum}-${i}`,
    img: `https://picsum.photos/300/${200 + Math.random() * 400 | 0}?${pageNum}-${i}`,
    desc: `第${pageNum}頁(yè)-${i+1}條`
  }));
  return mockData;
};
 
// 分配元素到最短列
const assignToShortestColumn = (data) => {
  data.forEach(item => {
    // 找到最短列的索引
    const minHeightIndex = columnHeights.value.indexOf(Math.min(...columnHeights.value));
    // 插入元素
    columnList.value[minHeightIndex].push(item);
    // 預(yù)估值(圖片加載前先占位,避免高度計(jì)算偏差)
    columnHeights.value[minHeightIndex] += 300; // 臨時(shí)占位高度
  });
};
 
// 圖片加載完成后更新列高度
const handleImgLoad = (id) => {
  nextTick(() => {
    // 找到當(dāng)前圖片元素
    const img = document.querySelector(`img[data-id="${id}"]`);
    if (!img) return;
    const item = img.closest('.waterfall-item');
    const column = item.closest('.waterfall-column');
    // 找到列索引
    const colIndex = columnRefs.value.findIndex(col => col === column);
    if (colIndex === -1) return;
    // 重新計(jì)算列高度
    columnHeights.value[colIndex] = column.offsetHeight;
  });
};
 
// 加載更多數(shù)據(jù)
const loadMore = async () => {
  const data = await fetchData(page);
  if (data.length === 0) {
    hasMore.value = false;
    return;
  }
  assignToShortestColumn(data);
  page++;
};
 
// 窗口大小變化時(shí)重新布局
const handleResize = () => {
  initColumns();
  // 重新分配所有數(shù)據(jù)(合并所有列數(shù)據(jù))
  const allData = columnList.value.flat();
  columnList.value = Array.from({ length: columnCount.value }, () => []);
  columnHeights.value = Array(columnCount.value).fill(0);
  assignToShortestColumn(allData);
};
 
// 初始化
onMounted(() => {
  initColumns();
  loadMore();
  // 監(jiān)聽(tīng)窗口變化(Vue3 內(nèi)置 onResize)
  onResize(handleResize);
});
</script>
 
<style scoped>
.waterfall-js {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px;
  /* 彈性布局實(shí)現(xiàn)列并排 */
  display: flex;
  gap: 16px; /* 列間距 */
}
 
.waterfall-column {
  /* 列寬均分 */
  flex: 1;
}
 
.waterfall-item {
  margin-bottom: 16px;
  border-radius: 8px;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  overflow: hidden;
}
 
.item-img {
  width: 100%;
  height: auto;
  display: block;
}
 
.item-desc {
  padding: 12px;
  font-size: 14px;
  color: #333;
}
 
/* 加載更多樣式 */
.load-more, .no-more {
  width: 100%;
  text-align: center;
  padding: 16px;
  font-size: 14px;
  color: #666;
  cursor: pointer;
}
 
.load-more:hover {
  color: #409eff;
}
 
.no-more {
  cursor: default;
  color: #999;
}
</style>

四、核心優(yōu)化技巧

1. 圖片加載優(yōu)化

  • 用 loading="lazy" 實(shí)現(xiàn)原生懶加載,減少首屏加載壓力;
  • 圖片加載前設(shè)置占位高度(避免列高度計(jì)算偏差);
  • 圖片加載完成后重新計(jì)算列高度(handleImgLoad 方法)。

2. 窗口適配

  • 監(jiān)聽(tīng) onResize 事件,動(dòng)態(tài)調(diào)整列數(shù)并重新分配元素;
  • 用 nextTick 確保 DOM 更新后再計(jì)算高度。

3. 性能優(yōu)化

  • 長(zhǎng)列表場(chǎng)景:結(jié)合 vue-virtual-scroller 實(shí)現(xiàn)虛擬列表,避免 DOM 過(guò)多;
  • 數(shù)據(jù)請(qǐng)求:防抖 / 節(jié)流加載更多,避免頻繁請(qǐng)求;
  • 樣式優(yōu)化:減少 offsetHeight 等重排操作,批量更新列數(shù)據(jù)。

4. 兼容處理

  • 低版本瀏覽器:替換 Array.flat() 等 ES6+ 方法,或引入 polyfill;
  • 圖片加載失?。禾砑?nbsp;onerror 回調(diào),顯示默認(rèn)占位圖。

五、第三方庫(kù)推薦(懶人方案)

若不想手動(dòng)實(shí)現(xiàn),可使用成熟的 Vue3 瀑布流組件:

vue3-waterfall-easy:輕量、支持懶加載、響應(yīng)式,文檔友好;

npm install vue3-waterfall-easy --save 

vue-grid-layout:適用于可拖拽的瀑布流布局,支持自定義網(wǎng)格大小;

masonry-layout:經(jīng)典的瀑布流庫(kù),可結(jié)合 Vue3 封裝使用。

六、總結(jié)

  1. 快速實(shí)現(xiàn):用 CSS column-count 或 grid,適合靜態(tài)短列表;
  2. 生產(chǎn)環(huán)境:優(yōu)先用 JS 計(jì)算方案,保證排序正常、支持動(dòng)態(tài)加載;
  3. 核心邏輯:JS 方案的關(guān)鍵是「計(jì)算列高 → 插入最短列 → 圖片加載后更新高度」;
  4. 優(yōu)化重點(diǎn):圖片懶加載、窗口適配、減少重排操作。

可根據(jù)項(xiàng)目需求選擇方案:簡(jiǎn)單場(chǎng)景用 CSS,復(fù)雜場(chǎng)景(動(dòng)態(tài)加載、排序要求)用 JS 方案,或直接使用第三方庫(kù)提升開(kāi)發(fā)效率。

以上就是Vue3實(shí)現(xiàn)瀑布流的2種核心方案的詳細(xì)內(nèi)容,更多關(guān)于Vue3實(shí)現(xiàn)瀑布流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 你知道vue data為什么是一個(gè)函數(shù)

    你知道vue data為什么是一個(gè)函數(shù)

    本篇文章從javascript原型鏈來(lái)解釋為什么vue中data必須是一個(gè)函數(shù),解釋一下這部分的原理內(nèi)容,感興趣的朋友跟隨小編一起看看吧
    2021-11-11
  • vue3中傳遞路徑參數(shù)的限制

    vue3中傳遞路徑參數(shù)的限制

    在 Vue 3 里使用路由跳轉(zhuǎn)到用戶頁(yè)并傳遞路徑參數(shù)時(shí),存在一些限制和需要注意的方面,下面給大家分享vue3中傳遞路徑參數(shù)有什么限制,感興趣的朋友一起看看吧
    2025-03-03
  • Vue2 Watch監(jiān)聽(tīng)操作方法

    Vue2 Watch監(jiān)聽(tīng)操作方法

    這篇文章主要介紹了Vue2 Watch監(jiān)聽(tīng),通過(guò)watch監(jiān)聽(tīng)器,我們可以實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)的變化,并且在數(shù)據(jù)發(fā)生改變時(shí)進(jìn)行相應(yīng)的操作,需要的朋友可以參考下
    2023-12-12
  • vue Element-ui表格實(shí)現(xiàn)樹(shù)形結(jié)構(gòu)表格

    vue Element-ui表格實(shí)現(xiàn)樹(shù)形結(jié)構(gòu)表格

    這篇文章主要為大家詳細(xì)介紹了vue Element-ui表格實(shí)現(xiàn)樹(shù)形結(jié)構(gòu)表格,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • vue修改數(shù)據(jù)頁(yè)面無(wú)效的解決方案

    vue修改數(shù)據(jù)頁(yè)面無(wú)效的解決方案

    這篇文章主要介紹了vue修改數(shù)據(jù)頁(yè)面無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Vue實(shí)現(xiàn)路由守衛(wèi)的示例代碼

    Vue實(shí)現(xiàn)路由守衛(wèi)的示例代碼

    Vue路由守衛(wèi)是控制頁(yè)面導(dǎo)航的鉤子函數(shù),主要用于鑒權(quán)、數(shù)據(jù)預(yù)加載等場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09
  • 在Vue3中實(shí)現(xiàn)一個(gè)自定義的v-html組件方式

    在Vue3中實(shí)現(xiàn)一個(gè)自定義的v-html組件方式

    文章介紹了Vue.js中的v-html指令及其潛在的安全風(fēng)險(xiǎn),然后通過(guò)DOMParser實(shí)現(xiàn)了一個(gè)自定義的v-html組件,以提高安全性并避免XSS攻擊
    2025-11-11
  • Vue中.env文件的使用詳解

    Vue中.env文件的使用詳解

    在Vue項(xiàng)目開(kāi)發(fā)中,.env文件用于配置不同環(huán)境(開(kāi)發(fā)、測(cè)試、生產(chǎn))的環(huán)境變量,通過(guò)不同的文件如.env.development和.env.production來(lái)區(qū)分環(huán)境配置,Vue會(huì)根據(jù)運(yùn)行命令自動(dòng)加載對(duì)應(yīng)的配置文件,如使用npm run serve會(huì)加載.env.development
    2024-11-11
  • vue router仿天貓底部導(dǎo)航欄功能

    vue router仿天貓底部導(dǎo)航欄功能

    這篇文章主要介紹了vue router仿天貓底部導(dǎo)航欄功能,需要的朋友可以參考下
    2017-10-10
  • vue里的axios如何獲取本地json數(shù)據(jù)

    vue里的axios如何獲取本地json數(shù)據(jù)

    這篇文章主要介紹了vue里的axios如何獲取本地json數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評(píng)論

远安县| 永顺县| 微博| 黑河市| 汉寿县| 合肥市| 融水| 南川市| 江口县| 芷江| 剑阁县| 海伦市| 顺昌县| 扶沟县| 铁力市| 虹口区| 抚州市| 阳谷县| 渝中区| 通许县| 福建省| 普兰店市| 太白县| 米泉市| 梓潼县| 英德市| 镇远县| 望谟县| 陆丰市| 湘潭市| 光泽县| 离岛区| 湖北省| 上蔡县| 乌苏市| 梁山县| 安达市| 平昌县| 黎川县| 酒泉市| 庆阳市|