Vue2瀑布流图片展示(Waterfall)

简介: 这篇文章介绍了如何在Vue 3框架中实现瀑布流图片展示组件,提供了两种实现方式:一种使用CSS的`column-count`和`column-gap`属性,另一种使用JavaScript计算图片位置,以实现图片在多列中的动态分布。

可自定义设置以下属性:

  • 瀑布流的图片数组(imageData),必传

  • 瀑布流要划分的列数(columnCount),默认3

  • 瀑布流各列之间的间隙(columnGap),默认30px

  • 瀑布流区域的总宽度(totalWidth),默认1200px

  • 瀑布流区域背景填充色(backgroundColor),默认'#F2F4F8'

主要使用两种方式实现:

  • 方式一:使用css的column-count和column-gap
  • 方式二:使用js获取每张图片宽高,结合relative和absolute定位计算每个图片的位置top,left,保证每张图片都追加在高度最小的那列末尾

方式一具体实现如下:(纯CSS,实现简单,但图片顺序是每列从上往下排列)

效果如下图:

①创建瀑布流展示组件Waterfall.vue:

<template>
  <div class="m-waterfall-wrap" :style="`background: ${backgroundColor}; width: ${width}px; padding: ${columnGap}px; column-count: ${columnCount}; column-gap: ${columnGap}px;`">
    <div class="m-img" :style="`margin-bottom: ${columnGap}px;`" v-for="(item, index) in imageData" :key="index">
      <img class="u-img" :src="item.imgUrl" :title="item.title" :alt="item.title" />
    </div>
  </div>
</template>
<script>
/*
  纯CSS,实现简单,但图片顺序是每列从上往下排列
*/
export default {
  name: 'Waterfall',
  props: {
    imageData: { // 瀑布流的图片数组
      type: Array,
      required: true,
      default: () => {
        return []
      }
    },
    columnCount: { // 瀑布流要划分的列数
      type: Number,
      default: 3
    },
    columnGap: { // 瀑布流各列之间的间隙
      type: Number,
      default: 30
    },
    totalWidth: { // 瀑布流区域的总宽度
      type: Number,
      default: 1200
    },
    backgroundColor: { // 瀑布流区域背景填充色
      type: String,
      default: '#F2F4F8'
    }
  },
  computed: {
    width () {
      return this.totalWidth - 2 * this.columnGap
    }
  }
}
</script>
<style lang="less" scoped>
.m-waterfall-wrap {
  .m-img {
    .u-img {
      width: 100%;
      vertical-align: bottom;
    }
  }
}
</style>

②在要使用的页面引入:

<Waterfall
    :imageData="imageData"
    :columnCount="3"
    :columnGap="30"
    :totalWidth="900"
    backgroundColor="skyblue" />
import Waterfall from '@/components/Waterfall'
components: {
    Waterfall
}
imageData: [
    {
        title: 'image-1',
        imgUrl: require('@/assets/images/1.jpg')
    },
    {
        title: 'image-2',
        imgUrl: require('@/assets/images/2.jpg')
    },
    {
        title: 'image-3',
        imgUrl: require('@/assets/images/3.jpg')
    },
    {
        title: 'image-4',
        imgUrl: require('@/assets/images/4.jpg')
    },
    {
        title: 'image-5',
        imgUrl: require('@/assets/images/5.jpg')
    },
    {
        title: 'image-6',
        imgUrl: require('@/assets/images/6.jpg')
    },
    {
        title: 'image-7',
        imgUrl: require('@/assets/images/7.jpg')
    },
    {
        title: 'image-8',
        imgUrl: require('@/assets/images/8.jpg')
    }
]

方式二具体实现如下(主要使用js进行计算,新的图片每次都添加在最短那列的末尾)

效果如下图:

①创建瀑布流展示组件Waterfall.vue:

<template>
  <div class="m-waterfall-wrap" :style="`background-color: ${backgroundColor}; width: ${totalWidth}px; height: ${height}px;`">
    <img
      class="u-img"
      v-for="(item, index) in imagesProperty"
      :key="index"
      :style="`width: ${imageWidth}px; top: ${item && item.top}px; left: ${item && item.left}px;`"
      :src="imageData[index].imgUrl"
      :title="imageData[index].title"
      :alt="imageData[index].title" />
  </div>
</template>
<script>
/*
  主要使用js进行计算,新的图片每次都添加在最短那列的末尾
*/
export default {
  name: 'Waterfall',
  props: {
    imageData: { // 瀑布流的图片数组
      type: Array,
      required: true,
      default: () => {
        return []
      }
    },
    columnCount: { // 瀑布流要划分的列数
      type: Number,
      default: 3
    },
    columnGap: { // 瀑布流各列之间的间隙
      type: Number,
      default: 30
    },
    totalWidth: { // 瀑布流区域的总宽度
      type: Number,
      default: 1200
    },
    backgroundColor: { // 瀑布流区域背景填充色
      type: String,
      default: '#F2F4F8'
    }
  },
  data () {
    return {
      imagesProperty: [],
      preImages: new Array(this.columnCount)
    }
  },
  computed: {
    imageWidth () {
      return (this.totalWidth - 4 * this.columnGap) / this.columnCount
    },
    height () {
      return Math.max(...this.preImages) + this.columnGap
    }
  },
  watch: {
    imageData (to) {
      this.onPreload()
      this.imagesProperty.splice(to.length)
    }
  },
  created () {
    if (this.imageData.length) {
      this.onPreload()
      this.imagesProperty.splice(this.imageData.length)
    }
  },
  methods: {
    getPosition (i, height) { // 获取图片位置信息(top,left)
      if (i < this.columnCount) {
        this.$set(this.preImages, i, this.columnGap + height)
        return {
          top: this.columnGap,
          left: (this.imageWidth + this.columnGap) * i + this.columnGap
        }
      } else {
        const top = Math.min(...this.preImages)
        var index = 0
        for (let n = 0; n < this.preImages.length; n++) {
          if (this.preImages[n] === top) {
            index = n
            break
          }
        }
        this.$set(this.preImages, index, top + this.columnGap + height)
        return {
          top: top + this.columnGap,
          left: (this.imageWidth + this.columnGap) * index + this.columnGap
        }
      }
    },
    onLoad (url, i) {
      return new Promise((resolve) => {
        const image = new Image()
        image.src = url
        const that = this
        image.onload = function () { // 图片加载完成时执行,此时可通过image.width和image.height获取到图片原始宽高
          var height = image.height / (image.width / that.imageWidth)
          that.$set(that.imagesProperty, i, { // 存储图片宽高和位置信息
            width: that.imageWidth,
            height: height,
            ...that.getPosition(i, height)
          })
          // console.log('this:', this === image) // true 函数运行时所在的对象即img
          resolve('load')
        }
      })
    },
    async onPreload () { // 计算图片宽高和位置(top,left)
      const len = this.imageData.length
      for (let i = 0; i < len; i++) {
        await this.onLoad(this.imageData[i].imgUrl, i)
      }
    }
  }
}
</script>
<style lang="less" scoped>
.m-waterfall-wrap {
  position: relative;
  .u-img {
    position: absolute;
    display: inline-block;
    object-fit: contain;
    vertical-align: bottom;
  }
}
</style>

②在要使用的页面引入:

<Waterfall
    :imageData="imageData"
    :columnCount="3"
    :columnGap="30"
    :totalWidth="900"
    backgroundColor="skyblue" />
import Waterfall from '@/components/Waterfall'
components: {
    Waterfall
}
imageData: [
    {
        title: 'image-1',
        imgUrl: require('@/assets/images/1.jpg')
    },
    {
        title: 'image-2',
        imgUrl: require('@/assets/images/2.jpg')
    },
    {
        title: 'image-3',
        imgUrl: require('@/assets/images/3.jpg')
    },
    {
        title: 'image-4',
        imgUrl: require('@/assets/images/4.jpg')
    },
    {
        title: 'image-5',
        imgUrl: require('@/assets/images/5.jpg')
    },
    {
        title: 'image-6',
        imgUrl: require('@/assets/images/6.jpg')
    },
    {
        title: 'image-7',
        imgUrl: require('@/assets/images/7.jpg')
    },
    {
        title: 'image-8',
        imgUrl: require('@/assets/images/8.jpg')
    }
]
相关文章
|
JavaScript 前端开发
vue3瀑布流布局(使用 Vue 3 框架的单文件组件格式(Single-File Component)编写的)
vue3瀑布流布局(使用 Vue 3 框架的单文件组件格式(Single-File Component)编写的)
843 0
|
6月前
|
JavaScript 前端开发 算法
Vue 与 React 深度对比:底层原理、开发体验与实际性能
本文深入对比Vue 3/Vue 4与React 19的核心原理、性能差异与开发体验。Vue基于Proxy响应式与编译优化,追求自动高效;React依托虚拟DOM、Fiber架构与并发渲染,强调灵活可控。两者在更新粒度、语法范式、学习曲线和生态上各有优劣。Vue适合快速开发与中小型项目,React更适配复杂交互与高定制需求。未来Vue趋向信号机制与Vapor Mode,React发力服务端组件与自动记忆化。选择应基于团队能力、项目场景与维护成本,追求技术适配性而非先进性。
1045 7
|
3月前
|
人工智能 自然语言处理 数据挖掘
智能体来了:从 0 到 1 搭建属于你的 AI 工作流
AI 正在从“对话工具”升级为“工作伙伴”。越来越多的工作可以通过 AI 工作流自动完成,例如信息整理、内容生成、数据分析与流程执行。本文从 0 到 1 介绍什么是 AI 工作流、为什么每个人都值得拥有自己的 AI 工作流,以及如何一步步搭建一个真正能提升效率的个人 AI 工作流系统。
1395 0
|
8月前
|
存储 数据安全/隐私保护
如何在 Vuex 中使用插件进行状态持久化?
如何在 Vuex 中使用插件进行状态持久化?
867 122
|
资源调度 JavaScript
Vue2拖拽插件(vuedraggable)
这篇文章介绍了如何在Vue 3框架中使用`vuedraggable`插件来实现拖拽功能,并提供了插件的安装、配置和事件处理的示例。
1810 1
Vue2拖拽插件(vuedraggable)
|
JavaScript
Vue3瀑布流(Waterfall)
这是一个基于 Vue2 的瀑布流(Waterfall)组件,支持多种自定义属性,如图片数组、列数、间隙、宽度、圆角、背景色及 Spin 加载样式。组件通过计算每张图片的位置实现动态布局,并利用 Vue 的响应式系统自动调整布局。提供了在线预览和详细代码示例,方便集成到项目中。
1021 1
Vue3瀑布流(Waterfall)
|
缓存 JavaScript 搜索推荐
vue中的一个内置组件Keep-Alive的作用及使用方法介绍——缓存不活动的组件实例
vue中的一个内置组件Keep-Alive的作用及使用方法介绍——缓存不活动的组件实例
1343 1
|
资源调度 JavaScript 前端开发
Vue2项目使用v-viewer插件实现图片预览、切换、缩放、旋转...
这篇文章介绍了在Vue 2项目中如何通过`v-viewer`插件实现图片的预览、切换、缩放、旋转等功能,并提供了插件的安装、配置和使用方法。
5340 0
Vue2项目使用v-viewer插件实现图片预览、切换、缩放、旋转...
【vue2】切换页面之后滚动条停留在上个页面的位置,解决方案
【vue2】切换页面之后滚动条停留在上个页面的位置,解决方案
1126 6
|
JavaScript UED
基于Vue2.0仿Element UI的el-tooltip实现一个气泡框组件,支持多数据类型的显示和内容为空时不显示气泡框
该文章介绍了如何基于Vue2.0仿照Element UI的el-tooltip组件实现一个自定义的气泡框组件,该组件能够根据内容是否为空智能显示或隐藏,支持多种数据类型的显示。
590 0
基于Vue2.0仿Element UI的el-tooltip实现一个气泡框组件,支持多数据类型的显示和内容为空时不显示气泡框