类小红书的社交卡片瀑布流

接到一个瀑布流布局的需求,网上找了一遍也没有找到合适的实现方式。无奈之下只能自己实现了。

先看效果:

实现思路

  1. 遍历列表创建异步任务(用任务队列管理),单个任务渲染一个卡片(计算获取最短列,然后将卡片推入最短列中)
  2. 使用 IntersectionObserver 监听加载,当滚动到底部时加载更多数据。

废话不多说,上代码吧

瀑布流渲染逻辑

这里进行了浅对比,如果判断是新增元素的情况,则不需要全部重新渲染,只需要将新增的数据创建对应异步任务即可

scss 复制代码
​
watch(
    [() => props.list],
    ([list], [prevList]) => {
        // 判断是不是新增了元素
        if (Array.isArray(list) && Array.isArray(prevList) && list.length > prevList.length && shallowCompareFirstNElements(list, prevList, prevList.length)) {
            const newArr = list.slice(prevList.length);
            distributeNewItems(newArr);
        } else {
            taskQueue.clear();
            initColumns();
            if (list.length > 0) {
                distributeNewItems(list);
            }
        }
    },
    {
        immediate: true,
    }
)

列高度计算逻辑

ini 复制代码
// 计算列高度
const updateColumnHeights = async () => {
    await nextTick();
    columns.value?.forEach(column => {
        const element = document.getElementById(column.id);
        if (element) {
            const rect = element.getBoundingClientRect();
            column.height = rect.height ?? 0;
        }
    });
};

异步任务创建逻辑

scss 复制代码
// 追加新数据到瀑布流
const distributeNewItems = (newItems: any[]) => {
    newItems.forEach(item => {
        const task = () => new Promise(async (resolve, reject) => {
            try {
                await updateColumnHeights()
                const shortestIndex = findShortestColumnIndex();
                columns.value[shortestIndex].items.push({ data: item, imageLoaded: () => resolve('') });
                if (!props.hasImage) {
                    resolve('');
                }
            } catch (err) {
                console.log(err);
                reject(err);
            }
        });
        taskQueue.enqueue(task);
    });
};

完整的逻辑请看可查看git仓库: github.com/KaiEi1020/w...

demo 还比较粗糙,有什么问题和建议欢迎讨论

相关推荐
JuneXcy15 分钟前
11.Layout-Pinia优化重复请求
前端·javascript·css
子洋24 分钟前
快速目录跳转工具 zoxide 使用指南
前端·后端·shell
天下无贼!25 分钟前
【自制组件库】从零到一实现属于自己的 Vue3 组件库!!!
前端·javascript·vue.js·ui·架构·scss
CF14年老兵1 小时前
✅ Next.js 渲染速查表
前端·react.js·next.js
司宸1 小时前
学习笔记八 —— 虚拟DOM diff算法 fiber原理
前端
阳树阳树1 小时前
JSON.parse 与 JSON.stringify 可能引发的问题
前端
让辣条自由翱翔1 小时前
总结一下Vue的组件通信
前端
dyb1 小时前
开箱即用的Next.js SSR企业级开发模板
前端·react.js·next.js
前端的日常1 小时前
Vite 如何处理静态资源?
前端
前端的日常1 小时前
如何在 Vite 中配置路由?
前端