Skip to content

多列照片墙实现

属性

{
  // 列数(由总宽度与每列宽度计算得出)
  columnCount: 0,
  // 列默认宽度
  columnDefaultWidth: 250,
  // 每列宽度(PC端等于列默认宽度,移动端等于屏幕宽度)
  columnWidth: 0,
  // 设置列与列之间的间距
  columnGap: 5,
  // 所有列中最大高度
  columnMaxHeight: 0,
  // 记录列高度数组
  columnHeightArr: [],
  // 所有图片
  imageList: [],
}
{
  // 列数(由总宽度与每列宽度计算得出)
  columnCount: 0,
  // 列默认宽度
  columnDefaultWidth: 250,
  // 每列宽度(PC端等于列默认宽度,移动端等于屏幕宽度)
  columnWidth: 0,
  // 设置列与列之间的间距
  columnGap: 5,
  // 所有列中最大高度
  columnMaxHeight: 0,
  // 记录列高度数组
  columnHeightArr: [],
  // 所有图片
  imageList: [],
}

原理

1、计算需要展示的列数、列宽、列与列之间的间隙。

function calculate() {
  let columnCount = 2
  let columnGap = 5
  let columnWidth = (window.innerWidth - 10 - columnGap) / 2

  columnCount = columnCount > 4
    ? 4
    : columnCount < 1
      ? 1
      : columnCount

  return {
    columnCount,
    columnGap,
    columnWidth
  }
}
function calculate() {
  let columnCount = 2
  let columnGap = 5
  let columnWidth = (window.innerWidth - 10 - columnGap) / 2

  columnCount = columnCount > 4
    ? 4
    : columnCount < 1
      ? 1
      : columnCount

  return {
    columnCount,
    columnGap,
    columnWidth
  }
}

2、加载图片判断当前图片应该显示在哪列,并重新计算当前列的高度以及列的最大高度。

javascript
  async load(arr) {
    for (let i = 0; i < arr.length; i++) {
      let url = arr[i]
      let image = await asyncLoadImage(url).catch(err => {
        console.log('err 加载图片错误:', url, err)
      })

      if (!image) return

      let finalHeight = (this.columnWidth) / (image.width / image.height) + this.columnGap
      // console.log(image.width, image.height, finalHeight)

      let min = Math.min(...this.columnHeightArr)
      let minIndex = this.columnHeightArr.indexOf(min)

      let item = {
        url,
        image,
        top: min,
        left: minIndex * (this.columnWidth + this.columnGap),
      }

      this.columnHeightArr[minIndex] = min + finalHeight

      this.setState({
        columnMaxHeight: Math.max(...this.columnHeightArr),
        imageList: this.state.imageList.concat(item)
      })
    }
  }
  async load(arr) {
    for (let i = 0; i < arr.length; i++) {
      let url = arr[i]
      let image = await asyncLoadImage(url).catch(err => {
        console.log('err 加载图片错误:', url, err)
      })

      if (!image) return

      let finalHeight = (this.columnWidth) / (image.width / image.height) + this.columnGap
      // console.log(image.width, image.height, finalHeight)

      let min = Math.min(...this.columnHeightArr)
      let minIndex = this.columnHeightArr.indexOf(min)

      let item = {
        url,
        image,
        top: min,
        left: minIndex * (this.columnWidth + this.columnGap),
      }

      this.columnHeightArr[minIndex] = min + finalHeight

      this.setState({
        columnMaxHeight: Math.max(...this.columnHeightArr),
        imageList: this.state.imageList.concat(item)
      })
    }
  }
html
  render() {
    return (<div className="list" style={{height: this.state.columnMaxHeight + 'px'}}>
      {
        this.state.imageList.map((item, idx) => {
          return (<div className="list-item" style={{
            width: this.columnWidth + "px",
            left: item.left + 'px',
            top: item.top + 'px'
          }} key={idx}>
            <img src={item.url}/>
          </div>)
        })
      }
    </div>)
  }
  render() {
    return (<div className="list" style={{height: this.state.columnMaxHeight + 'px'}}>
      {
        this.state.imageList.map((item, idx) => {
          return (<div className="list-item" style={{
            width: this.columnWidth + "px",
            left: item.left + 'px',
            top: item.top + 'px'
          }} key={idx}>
            <img src={item.url}/>
          </div>)
        })
      }
    </div>)
  }

2、如果图片下方还有文本,且长度不定,那就需要动态计算文本高度 + 图片的高度。

this.$nextTick(() => {
    if (title || desc) {
      let ele = this.$refs[imgItem.id][0];
      let bottomEle = ele.querySelectorAll('.bottom')[0];
      let {height} = bottomEle.getBoundingClientRect();
      imgItem.bottomHeight = height;
    }

    let w = this.columnWidth;
    let h = (w - 10) / (img.width / img.height);

    let minVal = Math.min(...this.columnHeightArr);
    let index = this.columnHeightArr.indexOf(minVal);

    let left = index * w;
    let top = minVal;

    imgItem.left = left;
    imgItem.top = top;
    imgItem.height = h;

    this.columnHeightArr[index] += (h + imgItem.bottomHeight + imgItem.padding);
    this.columnMaxHeight = Math.max(...this.columnHeightArr);
})
this.$nextTick(() => {
    if (title || desc) {
      let ele = this.$refs[imgItem.id][0];
      let bottomEle = ele.querySelectorAll('.bottom')[0];
      let {height} = bottomEle.getBoundingClientRect();
      imgItem.bottomHeight = height;
    }

    let w = this.columnWidth;
    let h = (w - 10) / (img.width / img.height);

    let minVal = Math.min(...this.columnHeightArr);
    let index = this.columnHeightArr.indexOf(minVal);

    let left = index * w;
    let top = minVal;

    imgItem.left = left;
    imgItem.top = top;
    imgItem.height = h;

    this.columnHeightArr[index] += (h + imgItem.bottomHeight + imgItem.padding);
    this.columnMaxHeight = Math.max(...this.columnHeightArr);
})