关于react.js:React-瀑布流实践

42次阅读

共计 4388 个字符,预计需要花费 11 分钟才能阅读完成。

需要

在业务中须要在 web 页面依据搜寻的后果渲染出瀑布流款式的后果页面,我实现成果如下(感觉不太称心,他并不是通过计算最小高度而后主动填补,而是依照几列几行来一个个填补,前面有更深刻的研究会更新,这是一种赶工实现的形式):

实现办法

尝试了间接应用 flex 布局,存在较大的缺点,尽管看似实现了,但对于特地的图片显示还是很奇怪,不够贴合,起初查问了几种插件,不是说他们都不好,试下的成果应该是相似的,都是通过计算图形的宽高来进行布局的,不过有些对于数据中蕴含的信息要求比拟高,让后盾在我的数据外面塞图形宽高曾经是我这个小前端的极限了!!最初找到了一个 react-grid-layout 插件,感激大佬小翼在答复中提供的几种插件。

代码

import React, {Component} from "react";
import styles from "./styles.module.less";
// 引入 lodash
import _ from "lodash";
// 引入组件
import RGL, {WidthProvider} from "react-grid-layout";
// 包装组件
const ReactGridLayout = WidthProvider(RGL);
// 定义案例数组数据
const items = [
  {
    url:
      "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=384124318,1246746555&fm=26&gp=0.jpg",
    width: 540,
    height: 300,
  },
  {
    url:
      "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2435568812,3959731342&fm=11&gp=0.jpg",
    width: 499,
    height: 320,
  },
  {
    url:
      "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3341500380,460051199&fm=11&gp=0.jpg",
    width: 604,
    height: 300,
  },
  {
    url:
      "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2435568812,3959731342&fm=11&gp=0.jpg",
    width: 499,
    height: 320,
  },
  {
    url:
      "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3341500380,460051199&fm=11&gp=0.jpg",
    width: 604,
    height: 300,
  },
  {
    url:
      "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3426709235,3578542279&fm=26&gp=0.jpg",
    width: 500,
    height: 210,
  },
  {
    url:
      "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1322120441,3602413475&fm=26&gp=0.jpg",
    width: 400,
    height: 183,
  },

  {
    url:
      "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3426709235,3578542279&fm=26&gp=0.jpg",
    width: 500,
    height: 210,
  },
  {
    url:
      "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3341500380,460051199&fm=11&gp=0.jpg",
    width: 604,
    height: 300,
  },
  {
    url:
      "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1322120441,3602413475&fm=26&gp=0.jpg",
    width: 400,
    height: 183,
  },
  {
    url:
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Farchive%2F3c7a5b24b38ac3216182e0bf026622801d10c3fa.jpg&refer=http%3A%2F%2Fi2.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1612319581&t=9486804e3256336fd0d2c2865d929d6c",
    width: 1728,
    height: 1080,
  },
  {
    url:
      "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.51yuansu.com%2Fpic3%2Fcover%2F02%2F85%2F29%2F5a61c19d6a659_610.jpg&refer=http%3A%2F%2Fpic.51yuansu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1612319668&t=aaa48c2a20b18f021f8058d7bd882dfb",
    width: 610,
    height: 1295,
  },
];

// 定义一个父组件,次要是为了进行容器大小的变动监听,而后动静设置高度
export default class About extends Component {constructor(props) {super(props);
    // 行高初始化,这是我本人的行高,依据以后容器大小计算出来的
    this.state = {rowHeight: 110};
  }
  componentDidMount() {
    // 初始化 size 监听函数
    this.screenChange();}
  // 卸载 size 监听函数
  componentWillUnmount() {window.removeEventListener("resize", this.resize);
  }
  // size 监听函数
  screenChange = () => {window.addEventListener("resize", this.resize);
  };

  // 区域宽高变动时触发行高的变动
  resize = () => {const box = document.getElementById("watar-fall");
    let width = box.clientWidth;
    let rowHeight = (width - 100) / 12;
    this.setState({rowHeight});
    console.log(width);
  };

  render() {
    // 将行高作为 props 传入子组件
    const {rowHeight} = this.state;
    return (<div className={styles.bside_main_container} id="watar-fall">
        <WaterFall rowHeight={rowHeight} items={items}></WaterFall>
      </div>
    );
  }
}

// 定义的瀑布流子组件,真是利用能够独自封装在内部
class WaterFall extends Component {
  // 默认的 props
  static defaultProps = {
    className: "layout",
    isDraggable: false,
    isResizable: false,
    cols: 12,
    rowHeight: 110,
  };
  constructor(props) {super(props);
    // 初始化定义 layout 和渲染的数据
    this.state = {layout: this.generateLayout([]), data: []};
  }

  // 加载的时候更新 layout 和 data
  componentDidMount() {
    this.setState({data: [...this.props.items],
      layout: this.generateLayout(this.props.items),
    });
  }
  // 生成每一个瀑布流内 item 的函数
  generateDOM = () => {const { data} = this.state;
    return _.map(_.range(data.length), function (i) {
      return (
        // 这里的 key 值和 layout 外面的要对应,所以不要用其余值代替
        <div key={i} className={styles.box}>
          {/* 在这里能够自定义你要的显示款式 */}
          <img src={data[i].url} alt="ff" style={{width: "100%"}}></img>
        </div>
      );
    });
  };

  // 生成 layout 的数组函数
  generateLayout = (items) => {
    // 循环数据返回相应的 layout
    return _.map(new Array(items.length), function (item, i) {
      // 在这里设置每一个图片的高度。我是通过图片的宽而后依据所占行的比例,计算出来的等比高度
      let y = (3 / items[i].width) * items[i].height;
      return {x: (i * 3) % 12, // 每个图片的起始 x 点,因为是 4 列,所以在 12 列外面是 3 列一个图片
        y: Math.floor(i / 4) * y, // 距离四个换行
        w: 3, // 图片占的列数
        h: y, // 计算所得的图片高度
        i: i.toString(), // layout 的 key 值};
    });
  };

  render() {
    return (<div className={styles.container}>
        {/* 传入参数并生成瀑布流 */}
        <ReactGridLayout layout={this.state.layout} {...this.props}>
          {this.generateDOM()}
        </ReactGridLayout>
      </div>
    );
  }
}

总结

这次根本的实现是这样,这个组件原本更弱小的中央应该是在可拖拽的方面,我这算是千里之堤; 溃于蚁穴了,前面如果有工夫再钻研一下其余瀑布流或者本人写一个 js 组件吧。(如果我写的有什么问题,欢送斧正!)

正文完
 0