Vue3瀑布流(Waterfall)

news2024/9/27 17:35:30

Vue2瀑布流(Waterfall) 

可自定义设置以下属性:

  • 图片数组(images),类型:Array<{title: string, src: string}>,默认 []

  • 要划分的列数(columnCount),类型:number,默认 3

  • 各列之间的间隙(columnGap),类型:number,单位px,默认 30

  • 瀑布流区域的总宽度(width),类型:number | string,默认 '100%'

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

  • 瀑布流排列方式(mode)类型:string,默认 'JS',可选:JS(js计算) CSS(css布局)

效果如下图:

JS计算模式(mode: 'JS')

CSS布局(mode: 'CSS')

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

<script setup lang="ts">
import { ref, onMounted, computed, watch } from 'vue'
/*
  mode: JS
  使用js进行计算,新的图片每次都添加在最短那列的末尾
  mode: CSS
  纯CSS,实现简单,但图片顺序是每列从上往下排列
*/
interface Image {
  title: string // 图片名称
  src: string // 图片地址
}
interface Props {
  images: Image[] // 图片数组
  columnCount?: number // 要划分的列数
  columnGap?: number // 各列之间的间隙
  width?: string|number // 瀑布流区域的总宽度
  backgroundColor?: string // 瀑布流区域背景填充色
  mode?: string // 瀑布流排列方式,可选:JS(js计算) CSS(css布局)
}
const props = withDefaults(defineProps<Props>(), {
  images: () => [],
  columnCount: 3,
  columnGap: 30,
  width: '100%',
  backgroundColor: '#F2F4F8',
  mode: 'JS'
})
const totalWidth = computed(() => {
  if (typeof props.width === 'number') {
    return props.width + 'px'
  } else {
    return props.width
  }
})

const imagesProperty = ref<any[]>([])
const preColumnHeight = ref<number[]>([]) // 每列的高度
const waterfall = ref()
const imageWidth = ref()
const height = computed(() =>{
  return Math.max(...preColumnHeight.value) + props.columnGap
})
watch(
() => props.images,
(to) => {
  if (to.length && props.mode === 'JS') {
    onPreload()
  }
})
onMounted(() => {
  if (props.images.length && props.mode === 'JS') {
    onPreload()
  }
})

function getPosition (i: number, height: number) { // 获取图片位置信息(top,left)
  if (i < props.columnCount) {
    preColumnHeight.value[i] = props.columnGap + height
    return {
      top: props.columnGap,
      left: (imageWidth.value + props.columnGap) * i + props.columnGap
    }
  } else {
    const top = Math.min(...preColumnHeight.value)
    var index = 0
    for (let n = 0; n < preColumnHeight.value.length; n++) {
      if (preColumnHeight.value[n] === top) {
        index = n
        break
      }
    }
    preColumnHeight.value[index] = top + props.columnGap + height
    return {
      top: top + props.columnGap,
      left: (imageWidth.value + props.columnGap) * index + props.columnGap
    }
  }
}
function onLoad (url: string, i: number) {
  return new Promise((resolve) => {
    const image = new Image()
    image.src = url
    image.onload = function () { // 图片加载完成时执行,此时可通过image.width和image.height获取到图片原始宽高
      var height = image.height / (image.width / imageWidth.value)
      imagesProperty.value[i] = { // 存储图片宽高和位置信息
        width: imageWidth.value,
        height: height,
        ...getPosition(i, height)
      }
      resolve('load')
    }
  })
}
async function onPreload () { // 计算图片宽高和位置(top,left)
  // 计算每列的图片宽度
  imageWidth.value = (waterfall.value.offsetWidth - (props.columnCount + 1) * props.columnGap) / props.columnCount
  const len = props.images.length
  imagesProperty.value.splice(len)
  for (let i = 0; i < len; i++) {
    await onLoad(props.images[i].src, i)
  }
}
</script>
<template>
  <div v-if="mode==='JS'" v-bind="$attrs" class="m-waterfall-js" ref="waterfall" :style="`background-color: ${backgroundColor}; width: ${totalWidth}; height: ${height}px;`">
    <img
      class="u-img"
      v-for="(property, index) in imagesProperty"
      :key="index"
      :style="`width: ${imageWidth}px; top: ${property && property.top}px; left: ${property && property.left}px;`"
      :src="images[index].src"
      :title="images[index].title"
      :alt="images[index].title" />
  </div>
  <div v-if="mode==='CSS'" v-bind="$attrs" class="m-waterfall-css" :style="`background: ${backgroundColor}; width: calc(${totalWidth} - ${2 * props.columnGap}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 images" :key="index">
      <img class="u-img" :src="item.src" :title="item.title" :alt="item.title" />
    </div>
  </div>
</template>
<style lang="less" scoped>
.m-waterfall-css {
  .m-img {
    .u-img {
      width: 100%;
      vertical-align: bottom;
    }
  }
}
.m-waterfall-js {
  position: relative;
  .u-img {
    position: absolute;
    display: inline-block;
    object-fit: contain;
    vertical-align: bottom;
  }
}
</style>

②在要使用的页面引入: 

<script setup lang="ts">
import { Waterfall } from './Waterfall.vue'
import { ref, onBeforeMount } from 'vue'
import { getImageUrl } from '@/utils/util'

const images = ref<any[]>([])

function loadImages () {
  for (let i = 1; i <= 10; i++) {
    images.value.push({
      title: `image-${i}`,
      src: getImageUrl(i)
    })
  }
  console.log(images.value)
}
onBeforeMount(() => { // 组件已完成响应式状态设置,但未创建DOM节点
  loadImages()
})
</script>
<template>
  <div>
    <h2 class="mb10">Waterfall 瀑布流基本使用 (默认使用JS计算进行布局展示)</h2>
    <Waterfall
      :images="images"
      :columnCount="3"
      :columnGap="30"
      :width="1100"
      mode="JS"
      backgroundColor="#F2F4F8" />
    <h2 class="mt30 mb10">瀑布流使用CSS布局展示 (mode: CSS)</h2>
    <Waterfall
      :images="images"
      :columnCount="3"
      :columnGap="30"
      :width="1100"
      mode="CSS"
      backgroundColor="#F2F4F8" />
  </div>
</template>
<style lang="less" scoped>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/430134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux下_多线程

线程 1. 为什么使用线程? 使用fork创建进程以执行新的任务&#xff0c;该方式的代价很高。多个进程间不会直接共享内存线程是进程的基本执行单元&#xff0c;一个进程的所有任务都在线程中执行&#xff0c;进程要想执行任务&#xff0c;必须得有线程&#xff0c;进程至少要有一…

11、响应数据

文章目录1、响应JSON1.1、引入开发场景1.2 、jackson.jar ResponseBody1、装填返回值处理器2、返回值初步处理3、获取并使用返回值处理器4、观察如何获取返回值处理器5、返回值处理器接口内部6、返回值处理器支持的类型7、返回值解析器原理1.3、HTTPMessageConverter 原理1、M…

c# 通过webView2模拟登陆小红书网页版,解析无水印视频图片,以及解决X-s,X-t签名验证【2023年4月15日】

一、c# WebView2简介 1.一开始使用WebBrowser&#xff0c;因为WebBrowser控件使用的是ie内核&#xff0c;经过修改注册表切换为Edge内核后&#xff0c; 发现Edge内核版本较低&#xff0c;加载一些视频网站提示“浏览器版本过低“&#xff0c;”视频无法加载“。 2.WebBrowser…

CentOS上PHP源码安装和配置

CentOS上PHP源码安装和配置 此文是在CentOS 7上已经部署了Nginx的基础上进行的 关于CentOS7上安装Nginx&#xff0c;可参考我之前的文章&#xff1a; CentOS上Nginx安装记录 我们现在在这个基础上安装PHP 7。 PHP里面概念挺多的&#xff0c;没想到安装这个PHP需要花那么多时…

SpringBoot 表单提交全局日期格式转换器

参考资料 SpringBoot–LocalDateTime格式转换(前端入参)SpringBoot InitBinder注解绑定请求参数 目录 一. 实现Converter<S, T>接口的方式二. 全局ControllerAdvice InitBinder注解的方式三. RequestMappingHandlerAdapter的方式四. 效果 分析 ⏹当前台的提交数据的Con…

JVM-0418

JVM-字节码篇 虚拟机体系结构 线程共享&#xff1a;堆、方法区 线程私有&#xff1a;虚拟机栈&#xff0c;本地方法栈&#xff0c;程序计数器。其中虚拟机栈中包括局部变量表&#xff0c;和操作数栈。 字节码文件概述 字节码文件是跨平台的吗&#xff1f; 是的 Java虚拟机…

Apache Log4j2(CVE-2021-4101)远程代码执行漏洞复现

文章目录前言影响范围黑盒发现复现准备JNDILADPRMI漏洞复现Dnslog数据外带使用工具进行反弹shell防御与绕过防御绕过参考前言 Apache log4j是Apache的一个开源项目&#xff0c;Java的日志记录工具(同logback)。 log4j2中存在JNDI注入漏洞&#xff0c;当程序记录用户输入的数据…

Qt Quick - FileDialog文件对话框

FileDialog文件对话框使用总结一、概述二、使用三、常用属性四、常用例子1. 单选打开文本文件2. 单选保存文本文件一、概述 FileDialog提供了一个基本的文件选择器的功能&#xff1a;它允许用户选择现有的文件或目录&#xff0c;或者创建新的文件名。 对话框最初是不可见的。…

【性能测试学习】2023最有效的7大性能测试技术(建议收藏)

进入互联网时代&#xff0c;性能测试显得越来越重要&#xff0c;移动应用、web应用和物联网应用都需要进行性能测试和性能调优&#xff0c;而进行性能和负载测试会产生了大量的数据&#xff0c;这些数据难以分析。除了数据分析&#xff0c;我们还会遇到其它一些困难和挑战。 今…

数据结构和算法学习记录——认识二叉搜索树及二叉搜索树的查找操作(递归以及迭代实现-查找操作、查找最大和最小元素)

目录 二叉搜索树 二叉搜索树的一些操作函数 二叉搜索树的查找操作Find 递归实现 迭代实现 查找最大和最小元素 查找最小元素的递归函数 查找最大元素的迭代函数 二叉搜索树 二叉搜索树&#xff08;BST&#xff0c;Binary Search Tree&#xff09;&#xff0c;也称二…

深入了解 Hugging Face 中的生成工具:Generate方法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

SSH升级

升级openssh版本一、安装telnet远程管理主机1、检查是否安装telnet2、安装telnet服务二、下载所需的安装包1、下载openssl、openssh、zlib安装包2、安装所需的相关软件3、备份原来的数据4、复制文件到/usr/local/bin/下增加执行权限一、安装telnet远程管理主机 1、检查是否安装…

通达信口袋支点选股公式编写和设置方法答疑

1、口袋支点选股公式成交量条件 在我编写的口袋支点选股公式中&#xff0c;成交量条件为成交量创10日新高。有网友提出&#xff0c;根据书中的定义&#xff0c;口袋支点成交量条件是成交量大于近10日下跌时的最大成交量。 这个问题确实是我没考虑周全&#xff0c;成交量创10日…

【5G NAS】NR 终端侧PDU建立过程以及数据包的过滤和映射

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

对数据去趋势

对数据去趋势 测量的信号可能显示数据中非固有的整体模式。这些趋势有时会妨碍数据分析&#xff0c;因此必须进行去趋势。 以具有不同趋势的两种心电图 (ECG) 信号为例。ECG 信号对电源干扰等扰动很敏感。加载信号并绘制它们。 load(ecgSignals.mat) t (1:length(ecgl));su…

LaTeX+Overleaf 论文速通教程

一、文本/排版二、章节和段落三、数学公式四、插入图片五、插入表格六、参考文献与交叉引用不使用BibTeX使用BibTeX(推荐)七、交叉引用label和refOverleaf开发界面 latex命令&#xff1a;\命令[可选参数]{必选参数} Latex项目组成&#xff1a; .tex&#xff1a;正文 .bib&…

如何对数据库进行优化

数据库是什么&#xff1f; 简单来说数据库就是将数据按照一定顺序存储到磁盘上的一个软件&#xff0c;我们平时写的sql语句&#xff0c;就是用数据库软件能识别的语言&#xff0c;对数据进行增删改查。其实数据本质上是不存在表里&#xff0c;而是存在磁盘上&#xff0c;所谓的…

掌握亚马逊,沃尔玛,东南亚平台的测评要点,测评事半功倍

测评其实最重要的两个点就是自己的资源和成号率 资源包括;商家资源&#xff0c;中介资源&#xff0c;礼品卡资源&#xff0c;还有买卖账号的渠道&#xff0c;ip资源 成号率这个直接影响的就是你个人投入成本的多&#xff0c;成号率越高&#xff0c;你的成本越低&#xff0c;但…

【Java版oj】day36Rational Arithmetic、Pre-Post

目录 一、Rational Arithmetic &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、Pre-Post &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 一、…

十七、小程序报错 真机调试预览失效 Error: Illegal Buffer

报错 电脑端微信开发者工具运行成功而真机调试预览失效 报错 MiniProgramError Illegal Buffer 报错 {errno: 600001, errMsg: “request:fail -200:net::ERR_CERT_COMMON_NAME_INVALID”} 前言&#xff1a;手头有个去年的微信小程序项目 年底甲方不在使用 所以停掉了服务器、…