uniapp 瀑布流 (APP+H5+微信小程序)

  • Post author:
  • Post category:uniapp


WaterfallsFlow.vue

<template>
  <view class="wf-page" :class="props?.paddingC ? 'paddingC' : ''">
    <!--    left    -->
    <view>
      <view id="left" ref="left" v-if="leftList.length">
        <view
          v-for="(item, index) in leftList"
          :key="index"
          class="wf-item"
          @tap="itemTap(item)"
        >
          <!-- #ifdef MP-WEIXIN -->
          //这里需要注意插槽id 必须是唯一id ,否则小程序显示异常
          <slot :name="`slot${item.customSId || item.id}`"></slot>
          <!-- #endif -->
          <!-- #ifndef MP-WEIXIN -->
          <slot :item="item" :index="index"></slot>
          <!-- #endif -->

          <!-- <slot :item="item" :index="index"></slot> -->
        </view>
      </view>
    </view>
    <!--    right    -->
    <view>
      <view id="right" ref="right" v-if="rightList.length">
        <view
          v-for="(item, index) in rightList"
          :key="index"
          class="wf-item"
          @tap="itemTap(item)"
        >
          <!-- #ifdef MP-WEIXIN -->
          //这里需要注意插槽id 必须是唯一id ,否则小程序显示异常
          <slot :name="`slot${item.customSId || item.id}`"></slot>
          <!-- #endif -->
          <!-- #ifndef MP-WEIXIN -->
          <slot :item="item" :index="index"></slot>
          <!-- #endif --></view
        >
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
// import App from "@/script/module/App.js";
import { axj } from "@/script/sdk/cloudfarm";
import {
  reactive,
  ref,
  onMounted,
  watch,
  nextTick,
  getCurrentInstance,
} from "vue";
import { onPageScroll, onShow, onPullDownRefresh } from "@dcloudio/uni-app";
import App from "@/script/module/App";
const props: any = defineProps({
  // 瀑布流列表
  wfList: {
    type: Array,
    require: true,
  },
  updateNum: {
    type: Number,
    default: 10,
  },
  updated: {
    //强制页面重新渲染
    type: Boolean,
    default: false,
  },
  paddingC: {
    //控制显示paddding  兼容之前瀑布流样式
    type: Boolean,
    default: false,
  },
});
const _this = getCurrentInstance();
let allList = ref([]);
let leftList = ref([]);
let rightList = ref([]);
let boxHeight = ref([]);
let mark = ref(0);
// 调用父组件
const emits = defineEmits(["itemTap", "notify"]);

// 瀑布流排序
const waterFall = () => {
  const i = mark.value;
  if (i === 0) {
    // 初始化,从左边开始插入
    leftList.value.push(allList.value[i]);
    // 更新左边列表高度
    nextTick(() => {
      getViewHeight(0);
    });
  } else if (i === 1) {
    // 第二个item插入,默认为右边插入
    rightList.value.push(allList.value[i]);
    // 更新右边列表高度
    nextTick(() => {
      getViewHeight(1);
    });
  } else {
    // 根据左右列表高度判断下一个item应该插入哪边
    const leftOrRight = boxHeight.value[0] >= boxHeight.value[1] ? 1 : 0;
    if (leftOrRight) {
      rightList.value.push(allList.value[i]);
    } else {
      leftList.value.push(allList.value[i]);
    }
    // 更新插入列表高度  setTimeout用来解决 多次数据push 计算高度错误问题
    setTimeout(() => {
      getViewHeight(leftOrRight);
    }, 0);
  }
};
// 获取列表高度
const getViewHeight = (leftOrRight) => {
  const query = uni.createSelectorQuery().in(this || _this);
  const id = leftOrRight ? "#right" : "#left";
  // 使用nextTick,确保页面更新结束后,再请求高度
  nextTick(() => {
    query
      .select(id)
      .boundingClientRect((res: any) => {
        res ? (boxHeight.value[leftOrRight] = res.height) : "";
        mark.value = mark.value + 1;
      })
      .exec();
  });
};
// item点击
const itemTap = (item) => {
  emits("itemTap", item);
};

const setWfList = (wfList) => {
  allList.value = wfList;
  waterFall();
};

let collect = () => {
  let requestParm = {
    topicModule: props?.topicModule,
    topicId: props?.topicId,
  };
  return new Promise((resolve, reject) => {
    App.client?.farm.Api_UserInteract.thumb(0, [requestParm], (err, res) => {
      if (res) {
        resolve(true);
      }
    });
  });
};

watch(
  () => props.wfList,
  () => {
    // 如果数据为空或新的列表数据少于旧的列表数据(通常为下拉刷新或切换排序或使用筛选器),初始化变量
    if (
      !props.wfList.length ||
      (props.wfList.length === props.updateNum &&
        props.wfList.length <= allList.value.length) ||
      props.updated
    ) {
      allList.value = [];
      leftList.value = [];
      rightList.value = [];
      boxHeight.value = [];
      mark.value = 0;
    }
    // 如果列表有值,调用waterfall方法
    if (props.wfList.length) {
      allList.value = props.wfList;
      waterFall();
    }
  },
  {
    immediate: true, // 初始化数据触发watch
    // deep: true, // 对 对象进行深度监听 ; 此处深度监听,如果数据改变(比如点赞)会导致页面重绘
  }
);
watch(
  () => mark.value,
  () => {
    const len = allList.value.length;
    if (mark.value < len && mark.value !== 0) {
      waterFall();
    } else {
      if (boxHeight.value.length >= 2) {
        let bHeight =
          boxHeight.value[0] > boxHeight.value[1]
            ? boxHeight.value[0]
            : boxHeight.value[1];
        emits("notify", bHeight);
      }
    }
  },
  {
    immediate: true, // 初始化数据触发watch
    deep: true, // 对 对象进行深度监听
  }
);
</script>

<style lang="scss" scoped>
$page-padding: 10px;
$grid-gap: 10px;
.wf-page {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: $grid-gap;
  // padding: 10px $page-padding;
}
.paddingC {
  padding: 10px $page-padding;
}
.wf-item {
  width: calc((100vw - 2 * #{$page-padding} - #{$grid-gap}) / 2);
  padding-bottom: $grid-gap;
}
</style>


waterfall.vue

//这里需要注意customSId 必须是唯一id ,否则小程序显示异常
<template>
 <WaterfallsFlow ref="wfListRef" :wfList="DataList" :updated="updated">
    <!-- #ifdef MP-WEIXIN -->
      <view
        class="item"
        v-for="(item, index) in DataList"
        :key="index"
        :slot="`slot${item.customSId}`"
      >
      //这里自己写插槽内容
        <view :item="item" ></view>
      </view>
      <!-- #endif -->
      <!-- #ifndef MP-WEIXIN -->
      <template v-slot="{ item }">
        <view class="item">
        	//这里自己写插槽内容
          <view :item="item" ></view>
        </view>
      </template>
      <!-- #endif -->
    </WaterfallsFlow>
</template>

<script lang="ts" setup >
import { reactive, ref, onMounted, watch } from "vue";
import { onPageScroll, onShow, onPullDownRefresh } from "@dcloudio/uni-app";
import WaterfallsFlow from "./WaterfallsFlow.vue";
const DataList = ref([
   {
      image:
        "https://ss.dev.yiyiny.com/digital/2023/04/25/00yqnc0wglmzhtqf.jpg?x-oss-process=image/quality,q_50",
      avatar:
        "https://cdn.pixabay.com/user/2015/10/12/02-06-28-605_250x250.jpg",
      nickName: 1,
      title:
        "非常好看的额图片,快起来这里买看的额图片,快起来这里买看的额图片,快起来这里买看的额图片,快起来这里买东西",
      isLike: true,
    },
    {
      image:
        "https://ss.dev.yiyiny.com/digital/2023/04/24/009vus6uglv9477m.jpeg?x-oss-process=image/quality,q_5",
      avatar:
        "https://cdn.pixabay.com/user/2015/10/12/02-06-28-605_250x250.jpg",
      nickName: 2,
      title: "这段文字要少",
      isLike: false,
    },
  ];)
</script>

<style scoped lang="scss">
</style>



版权声明:本文为weixin_43073383原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。