這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 在學習Grid佈局之時,我發現其是CSS中的一種強大的佈局方案,它將網頁劃分成一個個網格,可以任意組合不同的網格,做出各種各樣的佈局,在刷某書和某寶首頁時,我們發現其展示方式就是一種瀑布流,是一種流行的網站頁面佈局,視覺表現為參差不 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
在學習Grid佈局之時,我發現其是CSS中的一種強大的佈局方案,它將網頁劃分成一個個網格,可以任意組合不同的網格,做出各種各樣的佈局,在刷某書和某寶首頁時,我們發現其展示方式就是一種瀑布流,是一種流行的網站頁面佈局,視覺表現為參差不齊的多欄佈局,隨著頁面向下滾動,這種佈局會不斷載入數據塊並附加到當前尾部。採用瀑布流佈局的方式可以打破常規網站佈局排版,給用戶眼前一亮的新鮮感,更好的適應移動端。
因此結合二者,本文將通過grid佈局簡單實現一個瀑布流組件,該組件已開源上傳npm,可以直接安裝使用,Git地址在文尾。
實現效果:
實現原理
1、使用grid佈局將頁面分為無數個小網格,每個網格高度為1px。
.grid-content { display: grid; grid-auto-rows: minmax(1px, 1px); overflow: auto; }
2、寬度根據需要自定義的列數自動分配。
'grid-template-columns': `repeat(${props.columns}, 1fr)`,
3、根據每個卡片視窗的高度計算每個卡片需要跨越幾個網格(因為每個網格設置高為1px,所以高度就是需要跨越的網格數)
'grid-row-end': `span ${gridItem.value.clientHeight - 1}`
4、監聽瀑布流滾動事件,通過判斷滾動條距離底部的高度,在滾動到底部一定距離時載入更多的數據,以實現無限滾動。
主要代碼實現
gridContent
組件主要代碼,迴圈展示每個條目,根據自定義的列展示不同的列數量,根據觸底數據判斷獲取最新數據。監聽傳入的數據進行處理,目前只是做了簡單處理,後面將通過虛擬列表的形式,動態處理該數據,以增加性能。
<template> <div class="grid-content" ref="gridContent" :style="gridStyle" @scroll="getMoreData"> <grid-item v-for="item in showDataList" :key="item.dataIndex" :data="item"> <template #slot-scope="slotProps"> <slot name="slot-scope" :slotProps="slotProps"></slot> </template> </grid-item> </div> </template> <script lang="ts" setup> import GridItem from './gridItem.vue'; import { ref, watch } from 'vue'; const props = defineProps({ dataList: { type: Array, default: [] }, columns: { type: Number, default: 2 }, width: { type: Number, default: 300 }, height: { type: Number, default: 400 }, bottom:{ type: Number, default: 50 }, loading:{ type: Boolean, default: true } }) const emit=defineEmits(['getMoreData']); const gridStyle = ref({}); const showDataList = ref<any>([]) watch(() => props.dataList, (newValue) => { let tempData: any = []; newValue.forEach((item: any, index) => { tempData.push({ ...item, dataIndex: index }) }) showDataList.value = tempData; gridStyle.value = { 'grid-template-columns': `repeat(${props.columns}, 1fr)`, width:props.width + 'px', height:props.height + 'px' } }, { immediate: true,deep:true }) const isLoading=ref<boolean>(false); watch(()=>props.loading,(newValue:boolean)=>{ isLoading.value=newValue; }) const gridContent=ref<any>(null); //根據觸底數據判斷獲取最新數據 const getMoreData=()=>{ const scrollHeight = gridContent.value.scrollHeight || 0; const clientHeight = gridContent.value.clientHeight || 0; const scrollTop = gridContent.value.scrollTop || 0; if(scrollHeight - clientHeight - scrollTop < props.bottom && !isLoading.value){ isLoading.value=true; emit('getMoreData'); } } </script>
grid-item
組件代碼,主要通過獲取組件高度設置跨越的網格數,通過插槽展示每個卡片。<template> <div class="grid-item" :style="itemStyle"> <div ref="gridItem"> <slot name="slot-scope" :data="data"></slot> </div> </div> </template> <script lang="ts" setup> import { ref, onMounted } from 'vue'; defineProps({ data: { type: Object, default: () => { } } }) const gridItem = ref<any>(null); const itemStyle = ref({}) onMounted(() => { itemStyle.value = { 'grid-row-end': `span ${gridItem.value.clientHeight - 1}` } }) </script> <style scoped> .grid-item { grid-row-end: span 100; } </style>
使用示例
npm install @fcli/vue-grid-waterfall --save-dev 來安裝 在項目中使用 import VueGridWaterfall from '@fcli/vue-grid-waterfall'; const app=createApp(App) app.use(VueGridWaterfall);
使用示例:
<template> <div class="content"> <vue-grid-waterfall :data-list="dataList" :columns="3" @getMoreData="getMoreData" :loading="isLoading"> <template #slot-scope="{ slotProps }"> <div class="item" :style="{ height: slotProps.data.height, background: slotProps.data.color }">{{ slotProps.data.color }}</div> </template> </vue-grid-waterfall> </div> </template> <script setup lang="ts"> import vueGridWaterfall from './plugin/index.vue'; import { ref, onMounted } from 'vue' component: { vueGridWaterfall } const dataList = ref<any>([]); //獲取隨機顏色 const getRandomColor = () => { const getColor: any = (color: any) => { return (color += '0123456789abcdef'[Math.floor(Math.random() * 16)]) && (color.length == 6) ? color : getColor(color); }; return '#' + getColor('') } const getMoreData = () => { isLoading.value = true; getData() } const isLoading = ref(true); //獲取數據 const getData = () => { for (let i = 0; i < 100; i++) { dataList.value.push({ height: 50 + Math.random() * 50 + 'px', color: getRandomColor() }) } setTimeout(()=>{ isLoading.value = false; }) } onMounted(() => { getData() }) </script>