vue3 uniapp封装一个瀑布流组件

打印 上一主题 下一主题

主题 850|帖子 850|积分 2550

  1. 新增组件m-waterfall   这样就可以在页面直接使用 不用在引入了
  2. <template>
  3.         <view class="m-waterfall">
  4.                 <view id="m-left-column" class="m-column">
  5.                         <slot name="left" :leftList="leftList"></slot>
  6.                 </view>
  7.                 <view id="m-right-column" class="m-column">
  8.                         <slot name="right" :rightList="rightList"></slot>
  9.                 </view>
  10.         </view>
  11. </template>
  12. <script setup>
  13. /**
  14. * @param value  瀑布流数据
  15. * @param addTime 插入数据的时间间隔
  16. * @param keyIdData / id值,用于清除某一条数据时,根据此idKey名称找到并移除
  17. */
  18. import {
  19.                 computed,
  20.                 defineProps,
  21.                 toRefs
  22.         } from "vue"
  23.        
  24.         const props=defineProps({
  25.                 // 瀑布流数据
  26.                 value: {
  27.                          required: true,
  28.                         type: Array,
  29.                         default: ()=>[]
  30.                 },
  31.                 // 每次向结构插入数据的时间间隔,间隔越长,越能保证两列高度相近,但是对用户体验越不好
  32.                 addTime: {
  33.                         type: [Number, String],
  34.                         default: 200
  35.                 },
  36.                 // id值,用于清除某一条数据时,根据此idKey名称找到并移除
  37.                 keyIdData: {
  38.                         type: String,
  39.                         default: 'id'
  40.                 }
  41.         })
  42.         const {
  43.                 value,
  44.                 addTime,
  45.                 keyIdData
  46.         } = toRefs(props)
  47.         const leftList = ref([])
  48.         const rightList = ref([])
  49.         const tempList = ref([])
  50.         const copyFlowList= computed (()=> {
  51.                 return cloneData(value.value);
  52.         })
  53.        
  54.         watch(()=>value.value,(nVal,oVal)=>{
  55.                 let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0;
  56.                
  57.                 tempList.value = tempList.value.concat(cloneData(nVal.slice(startIndex)));
  58.                 splitData();
  59.        
  60.         })
  61.         onMounted(()=>{
  62.        
  63.                 tempList.value = cloneData(copyFlowList.value);
  64.                 setTimeout(()=>{
  65.                         splitData();
  66.                 },200)
  67.         })
  68.        
  69. const instance = getCurrentInstance()
  70.         const getysHeigth=(classd)=>{
  71.                 return new Promise((resolve, reject) => {
  72.                         uni.createSelectorQuery().in(instance)
  73.                             .select(classd)
  74.                             .boundingClientRect(data => {
  75.                                 if (data) {
  76.                                     resolve(data);
  77.                                 } else {
  78.                                     reject(new Error('获取节点信息失败'));
  79.                                 }
  80.                             })
  81.                             .exec();
  82.                     });
  83.         }
  84.         const splitData = async () => {
  85.        
  86.                 if (tempList.value.length==0) return;
  87.                 let leftRect = await getysHeigth('#m-left-column');
  88.                 let rightRect = await getysHeigth('#m-right-column');
  89.                 // 如果左边小于或等于右边,就添加到左边,否则添加到右边
  90.                 let item =tempList.value[0];
  91.                 // 解决多次快速上拉后,可能数据会乱的问题,因为经过上面的两个await节点查询阻塞一定时间,加上后面的定时器干扰
  92.                 // 数组可能变成[],导致此item值可能为undefined
  93.                 if (!item) return;
  94.                 if (leftRect.height < rightRect.height) {
  95.                         leftList.value.push(item);
  96.                 } else if (leftRect.height > rightRect.height) {
  97.                         rightList.value.push(item);
  98.                 } else {
  99.                         // 这里是为了保证第一和第二张添加时,左右都能有内容
  100.                         // 因为添加第一张,实际队列的高度可能还是0,这时需要根据队列元素长度判断下一个该放哪边
  101.                         if (leftList.value.length <= rightList.value.length) {
  102.                                 leftList.value.push(item);
  103.                         } else {
  104.                                 rightList.value.push(item);
  105.                         }
  106.                 }
  107.                 // 移除临时列表的第一项
  108.                 tempList.value.splice(0, 1);
  109.                 // 如果临时数组还有数据,继续循环
  110.                 if (tempList.value.length) {
  111.                         setTimeout(() => {
  112.                                 splitData();
  113.                         }, addTime)
  114.                 }
  115.         }
  116.         // 复制而不是引用对象和数组
  117.         const cloneData=(data)=>{
  118.                 if(data){
  119.                         return JSON.parse(JSON.stringify(data));
  120.                 }else{
  121.                         return [];
  122.                 }
  123.                
  124.         }
  125.        
  126. </script>
  127. <style lang="scss" scoped>
  128. .m-waterfall {
  129.         display: flex;
  130.         flex-direction: row;
  131.         align-items: flex-start;
  132. }
  133. .m-column {
  134.         display: flex;
  135.         flex: 1;
  136.         flex-direction: column;
  137.         height: auto;
  138. }
  139. .m-image {
  140.         width: 100%;
  141. }
  142. </style>
复制代码
组件利用

  1. <m-waterfall :value="product">
  2.                                 <!-- 左边数据 -->
  3.                                 <template v-slot:left="{leftList}">
  4.                                         <view @click="addDta" class="prodecutitem" v-for="(item,index) in leftList" :key="index">
  5.                                                 <view style="width: 100%;">
  6.                                                         <m-imgage :url="item.image"></m-imgage>
  7.                                                 </view>
  8.                                                 <view class="title">{{item.title}}</view>
  9.                                                 <view class="desc">{{item.title}}</view>
  10.                                         </view>
  11.                                 </template>
  12.                                 <!-- 右边数据 -->
  13.                                 <template v-slot:right="{rightList}">
  14.                                         <view class="prodecutitem" v-for="(item,index) in rightList" :key="index">
  15.                                                 <view>
  16.                                                         <m-imgage :url="item.image"></m-imgage>
  17.                                                 </view>
  18.                                                 <view class="title">{{item.title}}</view>
  19.                                                 <view class="desc">{{item.title}}</view>
  20.                                         </view>
  21.                                 </template>
  22.                         </m-waterfal>
  23. 数据
  24.         const product=ref([
  25.                 {
  26.                         title:'水果蔬菜1',
  27.                         image:imgSrc.value
  28.                 },
  29.                 {
  30.                         title:'水果蔬菜2',
  31.                         image:"https://img2.baidu.com/it/u=3893165480,918722033&fm=253&fmt=auto&app=120&f=JPEG?w=729&h=1215"
  32.                 },
  33.                 {
  34.                         title:'水果蔬菜3',
  35.                         image:imgSrc.value
  36.                 },
  37.                 {
  38.                         title:'水果蔬菜1',
  39.                         image:imgSrc.value
  40.                 },
  41.                 {
  42.                         title:'水果蔬菜3',
  43.                         image:imgSrc.value
  44.                 }
  45.         ])
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表