首页 > 其他分享 >React瀑布流

React瀑布流

时间:2022-10-08 20:57:26浏览次数:65  
标签:span 高度 React item 瀑布 columnHeights const document

前端页面样式修改的时候,要用到瀑布流样式,本来是想用flex直接换行显示,试了发现并不是想要的效果;真正的瀑布流是每项的宽度固定,高度不固定,自动填充到高度最小的列下面,还具有有上拉加载更多功能;网上大部分是js实现的瀑布流,react方式实现的比较少,这里记录一下

  1. 用数组记录每列高度,遍历item数组,将item添加到高度最小的列下面;
    renderItemList = () => {//上面图片,下面文字;图片为正方形或长方形,文字一行或两行
        const { itemList } = this.state;
        let columnHeights = [0, 0];//记录每列的高度
        return itemList.map((item, index) => {
            const width = (document.body.clientWidth - 80)/2;//计算图片宽度
            const height = (item.type==3) ? width : width * (200/335);//计算图片高度
            let columIndex = columnHeights[0] > columnHeights[1] ? 1 : 0;//最小高度列
            let top = columnHeights[columIndex];//item的top设置为最小高度列的高度
            let left = columIndex==0 ? 0 : (document.body.clientWidth - 80)/2 + 20;//item的left根据最小高度列设置
            const textHeight = Math.min(this.getTextSize(item.name).height, 72);//文字高度不同的话,需要计算文字高度
            columnHeights[columIndex] += (height + 96 + textHeight + 24);//更新最小高度列的高度,内容高度+间隔
            //item使用absolute定位,根据计算出来的top和left设置位置
            return <div onClick={onClick} style={{width, top, left, position: 'absolute'}}>
                <img
                    src={item.image}
                    style={{height}}
                />
                <div>
                    {item.name}
                </div>
            </div>
        });
    }
    getTextSize = (text) => {
        var span = document.createElement('span')
        var dom = document.createElement('div')
        dom.style.width = (document.body.clientWidth - 80)/2 - 40 + 'px';
        var result = {}
        result.width = span.offsetWidth
        result.height = span.offsetHeight
        span.style.visibility = "hidden";
        span.style.fontSize = '28px';
        span.style.lineHeight = '36px';//最好设置行高 方便项目中计算
        span.style.fontFamily = 'PingFangSC-Regular, PingFang SC';
        span.style.display = 'inline-block';
        dom.appendChild(span)
        document.body.appendChild(dom)
        if (typeof span.textContent !== 'undefined') {
          span.textContent = text
        } else {
          span.innerText = text
        }
        result.width = parseFloat(window.getComputedStyle(span).width) - result.width
        result.height = parseFloat(window.getComputedStyle(span).height) - result.height
        document.body.removeChild(dom);//删除节点
        // console.log('text size', text, result);
        return result
    }
    
  2. 设置父元素position为relative,计算父元素高度并设置;
    itemContainerWidth = document.body.clientWidth - 60;
    let columnHeights = [0, 0];
    itemList.forEach((item, index) => {
        const imgWidth = (document.body.clientWidth - 80)/2;
        const imgHeight = (item.type==3) ? imgWidth : imgWidth * (200/335);
        let columIndex = columnHeights[0] > columnHeights[1] ? 1 : 0;
        const textHeight = Math.min(this.getTextSize(item.name).height, 72);
        columnHeights[columIndex] += (imgHeight + 96 + textHeight + 24);
    });
    height = Math.max(columnHeights[0], columnHeights[1]) - 24;
    
    <div style={{ width: itemContainerWidth, height, position: 'relative' }}>
        {this.renderItemList()} 
    </div>
    
  3. 上拉加载更多,原来使用的都是列表,需要在外面包裹一层组件,这里发现不适合,所以改用自定义监听页面滚动事件判断;
    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll, true);
    }
    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll, true);
    }
    
    handleScroll = () => {
        const indexDiv = document.querySelector('#example .container > div');
        if (!indexDiv) return;
        if (indexDiv.scrollTop > indexDiv.scrollHeight - indexDiv.clientHeight - 200) {
            const { pageNo, hasMore, isLoading } = this.state;
            if (hasMore && !isLoading) {
                this.getSmartRecommendList(pageNo + 1);
            }
        }
    };
    

问题

  1. 内容显示不全,因为absolute元素不会占用空间,导致父元素高度为0,需要在render里面,计算所有行最大高度,设置为容器的高度;
  2. 直接使用span计算文字高度不对,需要在外面包裹一个div,指定div宽度为列的宽度;
  3. 在didMount里写window.addEventListener的scroll方法无效,需要把最后一个参数设置为true,window.addEventListener('scroll', this.handleScroll, true)在捕获阶段而不是在冒泡阶段执行事件;

参考链接

https://blog.csdn.net/qq_45473786/article/details/105814902
https://blog.csdn.net/lhz_19/article/details/120413374

标签:span,高度,React,item,瀑布,columnHeights,const,document
From: https://www.cnblogs.com/shenyuiOS/p/16770156.html

相关文章

  • ReactNative遇到info Installing required CocoaPods dependencies卡死的问题
    最近换了mac,第一次使用rn做ios的项目发现一个问题,在使用react-nativerun-ios的时候,会遇到infoInstallingrequiredCocoaPodsdependencies卡着一直不动,盲猜是install......
  • react setState设置深层级对象的属性
      要修改里面的内容 ......
  • React的零渲染问题及源码分析
    开门见山,先来看一张bug图(状态下面有个00)。预期是:状态为0时,2个组件不做渲染。现状:状态为0时,2个组件不做渲染,但是渲染出了00。零渲染bug代码如何修复零渲染问题初窥源码源......
  • #yyds干货盘点#Vue3的reactive
    最近一阶段在学习Vue3,Vue3中用 ​​reactive​​、​​ref​​ 等方法将数据转化为响应式数据,在获取时使用 ​​track​​ 往 ​​effect​​ 中收集依赖,在值改变时,使......
  • 一个 create-react-app v5 的问题
    前言前两天我准备用​​create-react-app​​创建一个新项目,然后我在命令行下执行npxcreate-react-appmy-app命令行下就会提示Needtoinstallthefollowingpackages:......
  • React 新的文档用到了哪些技术?
    前言beta.reactjs.orgReact的新的文档已经完成了70%并且呼吁社区进行翻译工作。新的文档采用了全新的架构​​next.js​​​+​​TailwindCSS​​,改版后的文档......
  • [TDD] 如何测试 React 异步组件?
    前言本文承接上文如何测试驱动开发React组件?​,这次我将继续使用@testing-library/react来测试我们的React应用,并简要简要说明如何测试异步组件。异步组件的测试内容......
  • react路由
    -react路由其实是借助BOM中的History对象实现的,专门有一个history.js的库,可以让操作history对象简单起来。用history.js可以通过两种方式创建路由对象:1、History.create......
  • [Typescript + React] Tip: Use generics in React to make dynamic and flexible com
    YoucanusegenericsinReacttomakeincrediblydynamic,flexiblecomponents.Here,ImakeaTablecomponentwithageneric'items'type.interfaceTableProp......
  • 直播小程序源码,实现瀑布流布局的两种方式
    直播小程序源码,实现瀑布流布局的两种方式实现方式方式一:在页面遍历数组时使用if判断当前下标是基数还是偶数,将一个数组拆分为两个数组左右显示 <viewclass="photos"......