uni-app、H5实现瀑布流效果封装,列可以自定义


文章目录

  • 前言
  • 一、效果
  • 二、使用代码
  • 三、核心代码
  • 总结


前言

最近做项目需要实现uni-app、H5实现瀑布流效果封装,网上搜索有很多的例子,但是代码都是不够完整的,下面来封装一个uni-app、H5都能用的代码。在小程序中,一个个item渲染可能出现问题,也通过加锁来解决问题。


一、效果

1、下面看一下实现的效果,我这里的商品图片是正方形是固定大小的,如果你想要图片不同效果,也是可以适配的。
请添加图片描述

二、使用代码

1、下面是封装的组件如何使用

<TBodyrefresher:data="goodsList":is-end="isEnd":is-loading="isLoading":is-refreshing="isRefreshing"@refresh="reset"@lower="fetchGoodsNextPage"><TTMultiColumnListclass="bg-#fafafa goods"column-gap="16rpx":list="[]":column-size="2"@ready="updateColumnOperator"><template #default="{ data, index }"><viewclass="items_content">//这个是你的商品item,自己封装<TTGoodsCellPure:key="index":obj="data"arrangement="imageCenter"@click-item="onClickItem"/></view></template></TTMultiColumnList></TBody>

2、关键是updateColumnOperator方法,需要请求数据的时候把数据放进去渲染。

const goodsListQuery = {limit: 30,offset: undefined as string | undefined,
}
const isLoading = ref(false)
const goodsList = ref<Array<any>>([])
const isEnd = ref(false)
const isRefreshing = ref(false)// 获取商品列表
async function fetchGoodsList(options: { offset?: string; limit?: number } = {}) {const { offset, limit = goodsListQuery.limit } = options//接口自己替换自己的const { data } = await $apis.xxxxxx({categoryId: categoryId.value === -1 ? undefined : categoryId.value,keyword: '',offset,limit,})return { offset: data?.offset, list: data?.list ?? [] }
}// 获取商品列表
async function fetchGoodsPage() {if (isLoading.value || isEnd.value)returntry {goodsListQuery.offset = undefinedisLoading.value = trueconst { list, offset } = await fetchGoodsList({ offset: goodsListQuery.offset })if (list?.length) {goodsList.value = listif (list.length < goodsListQuery.limit)isEnd.value = true}else {isEnd.value = true}goodsListQuery.offset = offsetnextTick(() => {columnOperator?.reset(list)})}finally {isLoading.value = false}
}//下一页
async function fetchGoodsNextPage() {if (isLoading.value || isEnd.value)returntry {isLoading.value = trueisRefreshing.value = trueconst { list, offset } = await fetchGoodsList({ offset: goodsListQuery.offset })if (list?.length) {goodsList.value.push(...list)if (list.length < goodsListQuery.limit)isEnd.value = true}else {isEnd.value = true}goodsListQuery.offset = offsetcolumnOperator?.append(list)}finally {isRefreshing.value = falseisLoading.value = false}
}

三、核心代码

1、核心代码TTMultiColumnList代码

<script lang="ts" setup>
import type { Ref } from 'vue'
import { getCurrentInstance, nextTick, onMounted, ref } from 'vue'
import type { ColumnItem, ColumnOperator, ColumnOperatorPredictor, ListItem } from '@/utils/multiColumn'const props = withDefaults(defineProps<{list: Array<ListItem>columnSize: numbercolumnGap: stringrowGap: string}>(),{columnSize: 2,columnGap: 'normal',rowGap: 'normal',},
)const emit = defineEmits<{(e: 'ready', operator: ColumnOperator): void
}>()function range(count: number) {return Array.from({ length: count }, (_, i) => i)
}function getEmptyColumns(columnSize: number) {return range(columnSize).map(() => [])
}let appendColumnDataPromise = Promise.resolve(true)
const columns = ref<Array<Array<ColumnItem>>>(getEmptyColumns(props.columnSize))
const ctx = getCurrentInstance()
const columnRefs: Ref<Array<() => Promise<number>>> = computed(() => columns.value.map((_, i) => () => new Promise((resolve, reject) => {const className = `.s_${i}_ccList`// #ifdef H5const rect = document.querySelector(className)?.getBoundingClientRect()resolve(rect?.height || 0 as number)// #endif// #ifndef H5uni.createSelectorQuery().in(ctx).select(className).boundingClientRect().exec(([rect]) => {resolve(rect.height as number)})// #endif
})))// 获取高度最小一列的索引
async function getMinHeightColumnIndex(): Promise<number> {const columnHeights = await Promise.all(columnRefs.value.map(async (getHeight, index) => ({ height: await getHeight(), index })))return columnHeights.reduce((index, item, i) => {const height = columnHeights[index].heightconst siblingHeight = item.heightreturn siblingHeight < height ? i : index}, 0)
}// 将元素一个一个地插入到高度最小的一列
async function gradientAppendToColumn(startIndex: number, list: Array<ListItem>) {if (startIndex >= list.length)return falseconst targetColumnIndex = await getMinHeightColumnIndex()const item = { index: startIndex, data: list[startIndex] }const targetColumn = columns.value[targetColumnIndex]if (Array.isArray(targetColumn))targetColumn.push(item)else columns.value[targetColumnIndex] = [item]// render next itemreturn await new Promise((resolve) => {nextTick(async () => {// #ifndef H5// 解决小程序渲染问题await new Promise(resolve => nextTick(() => resolve(true)))// #endifawait gradientAppendToColumn(startIndex + 1, list)resolve(true)})})
}async function appendColumnDataInQueue(list: Array<ListItem>) {// 解决小程序渲染问题const oldAppendColumnDataPromise = appendColumnDataPromiseappendColumnDataPromise = new Promise((resolve) => {const cb = () => {appendColumnData(list).then(() => resolve(true)).catch(() => resolve(false))}oldAppendColumnDataPromise.then(() => cb()).catch(() => cb())})return appendColumnDataPromise
}async function appendColumnData(list: Array<ListItem>): Promise<boolean> {return await new Promise((resolve) => {nextTick(async () => {await gradientAppendToColumn(0, list)resolve(true)})})
}// 重置
async function resetColumnData(list?: Array<ListItem>): Promise<void> {if (list) {await appendColumnDataInQueue([])columns.value = getEmptyColumns(props.columnSize)await appendColumnDataInQueue(list)}
}// 移除元素
function removeColumnData(fn: (v: any) => boolean) {const staled = [] as Array<{ row: number; col: number }>columns.value.forEach((cols, colIndex) => {cols.forEach((d, rowIndex) => {if (fn(d.data))staled.push({ row: rowIndex, col: colIndex })})})staled.forEach(({ row, col }) => {columns.value[col].splice(row, 1)})
}// 更新元素
function updateColumnData(fn: ColumnOperatorPredictor, data: ListItem) {let done = falsefor (let col = 0; col < columns.value.length; col++) {if (done)breakconst rows = columns.value[col]for (let row = 0; row < rows.length; row++) {if (fn(rows[row].data)) {rows[row] = { index: rows[row].index, data }done = truebreak}}}
}onMounted(() => resetColumnData(props.list))emit('ready', {append: appendColumnDataInQueue,reset: resetColumnData,remove: removeColumnData,update: updateColumnData,
})
</script><template><view:style="{'display': 'grid','grid-template-columns': `repeat(${columns.length}, 1fr)`,'column-gap': props.columnGap,'row-gap': props.rowGap,'padding-left': '18rpx','padding-right': '18rpx','margin-top': '16rpx',}"><viewv-for="(rows, colIndex) in columns":key="colIndex"><view:key="`${colIndex}_list`":class="`s_${colIndex}_ccList`"><viewv-for="(row, rowIndex) in rows":key="`${colIndex}_${rowIndex}`"><slot:data="row.data":index="row.index":column-index="colIndex":row-index="rowIndex"/></view></view></view></view>
</template>

2、核心代码multiColumn代码

export type ListItem = unknownexport interface ColumnItem {index: numberdata: ListItem
}export type ColumnOperatorPredictor = (item: ListItem) => booleanexport interface ColumnOperator {readonly append: (list: Array<ListItem>) => voidreadonly remove: (predict: ColumnOperatorPredictor) => voidreadonly update: (predict: ColumnOperatorPredictor, data: ListItem) => voidreadonly reset: (list?: Array<ListItem>) => void
}

总结

这就是uni-app、H5实现瀑布流效果封装,希望能帮助到你,有什么问题可以私信给我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/22938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ASP.NET MVC】使用动软(二)(10)

一、添加动软生成工程 按前文添加动态到工程 双击动软 完成新建数据库服务器后 &#xff0c;需要关闭重新打开 选择简单三层&#xff0c;注意保存位置 注意切换数据库&#xff1a; 生成后拷贝五个文件夹到工程目录 注意目录结构&#xff1a; 添加四个项目到原来的工程&…

React 在 html 中 CDN 引入(包含 antd、axios ....)

一、简介 cdn 获取推荐 https://unpkg.com&#xff0c;unpkg 是一个快速的全球内容交付网络&#xff0c;适用于 npm 上所有内容。 【必备】react 相关 cdn。附&#xff1a;github 官方文档获取、现阶段官方文档 CDN 网址。 <script crossorigin src"https://unpkg.com…

Vue3和TypeScript项目-移动端兼容

1 全局安装typescript 2 检测安装成功 3 写的是ts代码&#xff0c;但是最后一定要变成js代码&#xff0c;才能在浏览器使用 这样就会多一个js文件 3 ts语法 数组语法 对象语法 安装vue3项目 成功后进入app。安装依赖。因为我们用的是脚手架&#xff0c;要引入东西的时候不需要…

I.MX6ULL_Linux_驱动篇(44)linux MISC驱动

MISC 驱动也叫做杂项驱动&#xff0c;也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动&#xff0c;通常嵌套在 platform 总线驱动中&#xff0c;实现复杂的驱动&#xff0c;本章我们就来学习一下 MISC 驱动的编写…

Homer:一个简单的静态主页

什么是 Homer ? Homer 是一个完全静态的 html/js 仪表板&#xff0c;基于一个简单的 yaml 配置文件。它旨在由 HTTP 服务器提供服务&#xff0c;如果您直接通过 file:// 协议打开 index.html&#xff0c;它将无法工作。 安装 在群晖上以 Docker 方式安装。 在注册表中搜索 h…

蓝桥杯上岸每日N题 第八期 (全球变暖)!!!

蓝桥杯上岸每日N题第八期(全球变暖)&#xff01;&#xff01;&#xff01; 同步收录 &#x1f447; 蓝桥杯上岸必背&#xff01;&#xff01;&#xff01;(第五期BFS) 大家好 我是寸铁&#x1f4aa; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &am…

原型链污染攻击

原型链污染攻击 prototype 和 _proto_是什么 JavaScript中的类的简历 在JavaScript中&#xff0c;我们如果要定义一个类&#xff0c;需要以定义“构造函数”的方式来定义&#xff1a; function Foo() {this.bar 1 }new Foo() 解析&#xff1a; Foo函数的内容&#xff0c;就…

2023年华数杯数学建模A题思路代码分析 - 隔热材料的结构优化控制研究

# 1 赛题 A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性&#xff0c;在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前&#xff0c;由单根隔热材料 A 纤维编织成的织物&#xff0c;其热导率可以直接测出&#xff1b;但是 单根隔热…

山西电力市场日前价格预测【2023-08-06】

日前价格预测 预测明日&#xff08;2023-08-06&#xff09;山西电力市场全天平均日前电价为411.77元/MWh。其中&#xff0c;最高日前电价为457.52元/MWh&#xff0c;预计出现在19: 30。最低日前电价为370.37元/MWh&#xff0c;预计出现在13: 15。 价差方向预测 1&#xff1a; 实…

机器学习---概述(一)

文章目录 1.人工智能、机器学习、深度学习2.机器学习的工作流程2.1 获取数据集2.2 数据基本处理2.3 特征工程2.3.1 特征提取2.3.2 特征预处理2.3.3 特征降维 2.4 机器学习2.5 模型评估 3.机器学习的算法分类3.1 监督学习3.1.1 回归问题3.1.2 分类问题 3.2 无监督学习3.3 半监督…

前端(十一)——Vue vs. React:两大前端框架的深度对比与分析

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;Vue vs. React&#xff1a;两大前端框架的深度对比与分析 文章目录 前言概述原理与设计思想算法生态系统与社区支持API与语法性能与优化开发体验与工程化对比总结结语 前言 在当今快速发展的前端领…

软件设计原则

文章目录 一、软件设计原则1. 开闭原则2. 里氏代换原则3. 依赖倒转原则4. 接口隔离原则5. 迪米特法则6. 合成复用原则 一、软件设计原则 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程序员要尽量根据软件…

django使用mysql数据库

Django开 发操作数据库比使用pymysql操作更简单&#xff0c;内部提供了ORM框架。 下面是pymysql 和orm操作数据库的示意图&#xff0c;pymysql就是mysql的驱动&#xff0c;代码直接操作pymysql ,需要自己写增删改查的语句 django 就是也可以使用pymysql、mysqlclient作为驱动&a…

迁移学习:使用Restnet预训练模型构建高效的水果识别模型

目录 引言 1 迁移学习 1.1 什么是迁移学习 1.2 迁移学习能解决什么问题 1.3 迁移学习面临的三个问题 1.3.1 何时迁移 1.3.2 何处迁移 1.3.3 如何迁移 1.4 迁移学习的分类 1.4.1 按照学习方式的划分 1.4.2 按照使用方法的划分 2 Restnet网络 2.1 Restnet介绍 2.2 Re…

element-ui树形表格,左边勾选,右边显示选中的数据-功能(如动图)

功能如图 功能需求 表格树形表格勾选数据&#xff0c;右边显示对应勾选的数据内容&#xff0c;选中客户&#xff0c;自动勾选所有的店铺(子级)&#xff0c;选中其中一个店铺&#xff0c;自动勾选上客户(父级)&#xff0c;同时会存在只有客户&#xff08;下面没有子级的情况&am…

Apache Flink概述

Flink 是构建在数据流之上的一款有状态的流计算框架&#xff0c;通常被人们称为第三代大数据分析方案 第一代大数据处理方案&#xff1a;基于Hadoop的MapReduce 静态批处理 | Storm 实时流计算 &#xff0c;两套独立的计算引擎&#xff0c;难度大&#xff08;2014年9月&#x…

Java版工程行业管理系统源码-专业的工程管理软件-em提供一站式服务 em

​ Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目…

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xff0c;因为EEPROM按页进行组织&#xff0c;在连…

caj文件怎么转换成pdf?了解一下这种方法

caj文件怎么转换成pdf&#xff1f;如果你曾经遇到过需要将CAJ文件转换成PDF格式的情况&#xff0c;那么你一定知道这是一件麻烦的事情。幸运的是&#xff0c;现在有许多软件和工具可以帮助你完成这项任务。下面就给大家介绍一款使用工具。 【迅捷PDF转换器】是一款功能强大的工…

启动RocketMQ报错

说明&#xff1a;启动RocketMQ消费者时&#xff0c;报以下错误&#xff1a;java.lang.IllegalStateException&#xff1a;Failed to start RocketMQ push consumer. 解决&#xff1a;看下所有的监听器类&#xff0c;检查是不是有相同的消费者组名&#xff0c;注释掉其中一个即可…