领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

【JS 滚动加载瀑布流】瀑布流滚动加载

nixiaole 2025-03-25 16:05:33 知识剖析 7 ℃

之前分享了一篇关于如何实现瀑布流的demo。但瀑布流一般都是要结合滚动加载,因此今天补足这一块。完整demo可查看next-demo: next-demo - Gitee.com

示例图:

瀑布流滚动加载技术点

  1. 根据布局容器计算列宽和列数
  2. 根据列宽计算出图片渲染尺寸的宽高
  3. 在滚动加载组件里实现数据动态加载
  4. 容器宽度变化时,重新计算列宽和图片的渲染尺寸

滚动加载组件

  1. 使用视口监视器实现滚动加载,替代之前的监听滚动事件
  2. 数据加载结束,取消监视器监听事件

核心代码实现

  1. 根据容器宽度,定义布局列数,然后计算出列宽
//根据业务自行定义列数,边界值
const getColumnWidth = (node: HTMLElement, gap = 20) => {
  let COLUMN_COUNT = 2;
  if (node.clientWidth > 968 && node.clientWidth <= 1200 column_count='3;' else if node.clientwidth> 1200 && node.clientWidth <= 1400 column_count='4;' else if node.clientwidth> 1400 && node.clientWidth <= 1600 column_count='5;' else if node.clientwidth> 1600) {
    COLUMN_COUNT = 6;
  }
  return {
    column: COLUMN_COUNT,
    columnWidth: Math.floor((node.clientWidth - gap * (COLUMN_COUNT - 1)) / COLUMN_COUNT),
  }
}
  1. 根据列宽,实现图片渲染尺寸
const computedImageWH = async (url: string, width: number) => {
  const img = new Image();
  img.src = url;
  await new Promise(res => img.onload = res);
  return {
    w: width,
    h: Math.floor((img.naturalHeight / img.naturalWidth) * width),
    src: img.src,
  };
};

// 修改图片加载逻辑
  const loadImages = async (data:any[]) => {
    const newImages = await Promise.all(
      data.map(async (item) => {
        const res = await computedImageWH(item, columns.columnWidth);
        return { ...res };
      })
    );

    return newImages;
  };
  1. 图片动态加载和布局定位计算
const calculatePositions = async(data:any[]) => {
    const newPositions: Iposition[] = [];
    const tempHeights = [...columnHeights.current];

    const HEIGHT = (ITEM_PADDING * 2) + (BORDER_WIDTH * 2) + 20;
    data.forEach((img) => {
      // 计算元素高度
      const elementHeight = img.h + HEIGHT
      // 找到最小高度列
      const minHeight = Math.min(...tempHeights);
      const columnIndex = tempHeights.indexOf(minHeight);

      // 计算位置
      newPositions.push({
        left: columnIndex * (columns.columnWidth + GAP),
        top: minHeight
      });

      // 更新列高度(图片高度 + 间距)
      tempHeights[columnIndex] += elementHeight + GAP;
    });

    columnHeights.current = tempHeights;
    return newPositions;
  }
  1. 滚动加载获取数据,扁平化和出栈处理
const getData = async()=> {
    setLoading(true)
    const res = await POST('/api/list/img')
    if(res.code===0) {
      const {list=[],hasMore} = res.data
      if(hasMore) {
        //将每次新数据保存在data中,
        // 布局变化时,将data中的数据扁平化
        // 滚动加载时,将data中的数据出栈,
        // 然后重新计算布局
        data.push(list)
        setData([...data])
      }
      
      setHasMore(hasMore)
      
    }else {
      setLoading(false)
    }
  }
  1. 由于篇幅问题,滚动加载的组件暂不分享了,感兴趣的朋友可以看下完整demo

完整demo next-demo: next-demo - Gitee.com

Tags:

最近发表
标签列表