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

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

先看效果:

实现思路

  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 还比较粗糙,有什么问题和建议欢迎讨论

相关推荐
码事漫谈3 小时前
当AI开始“思考”:我们是否真的准备好了?
前端·后端
许杰小刀3 小时前
ctfshow-web文件包含(web78-web86)
android·前端·android studio
我是Superman丶4 小时前
Element UI 表格某行突出悬浮效果
前端·javascript·vue.js
恋猫de小郭4 小时前
你的代理归我了:AI 大模型恶意中间人攻击,钱包都被转走了
前端·人工智能·ai编程
xiaokuangren_4 小时前
前端css颜色
前端·css
hoiii1875 小时前
C# 基于 LumiSoft 实现 SIP 客户端方案
前端·c#
anOnion5 小时前
构建无障碍组件之Meter Pattern
前端·html·交互设计
小码哥_常5 小时前
Spring Boot配置diff:解锁配置管理新姿势
前端
小码哥_常5 小时前
告别onActivityResult!Android数据回传的3大痛点与终极解决方案
前端
hhcccchh5 小时前
1.2 CSS 基础选择器、盒模型、flex 布局、grid 布局
前端·css·css3