当前位置:   article > 正文

记录--Vue3基于Grid布局简单实现一个瀑布流组件

display:grid 瀑布流布局

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

前言

在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,在刷某书和某宝首页时,我们发现其展示方式就是一种瀑布流,是一种流行的网站页面布局,视觉表现为参差不齐的多栏布局,随着页面向下滚动,这种布局会不断加载数据块并附加到当前尾部。采用瀑布流布局的方式可以打破常规网站布局排版,给用户眼前一亮的新鲜感,更好的适应移动端。

因此结合二者,本文将通过grid布局简单实现一个瀑布流组件,该组件已开源上传npm,可以直接安装使用,Git地址在文尾。

实现效果:

实现原理

1、使用grid布局将页面分为无数个小网格,每个网格高度为1px。

  1. .grid-content {
  2. display: grid;
  3. grid-auto-rows: minmax(1px, 1px);
  4. overflow: auto;
  5. }

2、宽度根据需要自定义的列数自动分配。

   'grid-template-columns': `repeat(${props.columns}, 1fr)`,

3、根据每个卡片窗口的高度计算每个卡片需要跨越几个网格(因为每个网格设置高为1px,所以高度就是需要跨越的网格数)

'grid-row-end': `span ${gridItem.value.clientHeight - 1}`

4、监听瀑布流滚动事件,通过判断滚动条距离底部的高度,在滚动到底部一定距离时加载更多的数据,以实现无限滚动。

主要代码实现

gridContent 组件主要代码,循环展示每个条目,根据自定义的列展示不同的列数量,根据触底数据判断获取最新数据。监听传入的数据进行处理,目前只是做了简单处理,后面将通过虚拟列表的形式,动态处理该数据,以增加性能。

  1. <template>
  2. <div class="grid-content" ref="gridContent" :style="gridStyle" @scroll="getMoreData">
  3. <grid-item v-for="item in showDataList" :key="item.dataIndex" :data="item">
  4. <template #slot-scope="slotProps">
  5. <slot name="slot-scope" :slotProps="slotProps"></slot>
  6. </template>
  7. </grid-item>
  8. </div>
  9. </template>
  10. <script lang="ts" setup>
  11. import GridItem from './gridItem.vue';
  12. import { ref, watch } from 'vue';
  13. const props = defineProps({
  14. dataList: {
  15. type: Array,
  16. default: []
  17. },
  18. columns: {
  19. type: Number,
  20. default: 2
  21. },
  22. width: {
  23. type: Number,
  24. default: 300
  25. },
  26. height: {
  27. type: Number,
  28. default: 400
  29. },
  30. bottom:{
  31. type: Number,
  32. default: 50
  33. },
  34. loading:{
  35. type: Boolean,
  36. default: true
  37. }
  38. })
  39. const emit=defineEmits(['getMoreData']);
  40. const gridStyle = ref({});
  41. const showDataList = ref<any>([])
  42. watch(() => props.dataList, (newValue) => {
  43. let tempData: any = [];
  44. newValue.forEach((item: any, index) => {
  45. tempData.push({ ...item, dataIndex: index })
  46. })
  47. showDataList.value = tempData;
  48. gridStyle.value = {
  49. 'grid-template-columns': `repeat(${props.columns}, 1fr)`,
  50. width:props.width + 'px',
  51. height:props.height + 'px'
  52. }
  53. }, { immediate: true,deep:true })
  54. const isLoading=ref<boolean>(false);
  55. watch(()=>props.loading,(newValue:boolean)=>{
  56. isLoading.value=newValue;
  57. })
  58. const gridContent=ref<any>(null);
  59. //根据触底数据判断获取最新数据
  60. const getMoreData=()=>{
  61. const scrollHeight = gridContent.value.scrollHeight || 0;
  62. const clientHeight = gridContent.value.clientHeight || 0;
  63. const scrollTop = gridContent.value.scrollTop || 0;
  64. if(scrollHeight - clientHeight - scrollTop < props.bottom && !isLoading.value){
  65. isLoading.value=true;
  66. emit('getMoreData');
  67. }
  68. }
  69. </script>
grid-item 组件代码,主要通过获取组件高度设置跨越的网格数,通过插槽展示每个卡片。
  1. <template>
  2. <div class="grid-item" :style="itemStyle">
  3. <div ref="gridItem">
  4. <slot name="slot-scope" :data="data"></slot>
  5. </div>
  6. </div>
  7. </template>
  8. <script lang="ts" setup>
  9. import { ref, onMounted } from 'vue';
  10. defineProps({
  11. data: {
  12. type: Object,
  13. default: () => { }
  14. }
  15. })
  16. const gridItem = ref<any>(null);
  17. const itemStyle = ref({})
  18. onMounted(() => {
  19. itemStyle.value = { 'grid-row-end': `span ${gridItem.value.clientHeight - 1}` }
  20. })
  21. </script>
  22. <style scoped>
  23. .grid-item {
  24. grid-row-end: span 100;
  25. }
  26. </style>

使用示例

  1. npm install @fcli/vue-grid-waterfall --save-dev 来安装
  2. 在项目中使用
  3. import VueGridWaterfall from '@fcli/vue-grid-waterfall';
  4. const app=createApp(App)
  5. app.use(VueGridWaterfall);

使用示例:

  1. <template>
  2. <div class="content">
  3. <vue-grid-waterfall :data-list="dataList" :columns="3" @getMoreData="getMoreData" :loading="isLoading">
  4. <template #slot-scope="{ slotProps }">
  5. <div class="item" :style="{ height: slotProps.data.height, background: slotProps.data.color }">{{ slotProps.data.color
  6. }}</div>
  7. </template>
  8. </vue-grid-waterfall>
  9. </div>
  10. </template>
  11. <script setup lang="ts">
  12. import vueGridWaterfall from './plugin/index.vue';
  13. import { ref, onMounted } from 'vue'
  14. component: {
  15. vueGridWaterfall
  16. }
  17. const dataList = ref<any>([]);
  18. //获取随机颜色
  19. const getRandomColor = () => {
  20. const getColor: any = (color: any) => {
  21. return (color += '0123456789abcdef'[Math.floor(Math.random() * 16)]) && (color.length == 6) ? color : getColor(color);
  22. };
  23. return '#' + getColor('')
  24. }
  25. const getMoreData = () => {
  26. isLoading.value = true;
  27. getData()
  28. }
  29. const isLoading = ref(true);
  30. //获取数据
  31. const getData = () => {
  32. for (let i = 0; i < 100; i++) {
  33. dataList.value.push({ height: 50 + Math.random() * 50 + 'px', color: getRandomColor() })
  34. }
  35. setTimeout(()=>{
  36. isLoading.value = false;
  37. })
  38. }
  39. onMounted(() => {
  40. getData()
  41. })
  42. </script>

本文转载于:

https://juejin.cn/post/7280747572695973948

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/970924
推荐阅读
相关标签
  

闽ICP备14008679号