Vue3瀑布流(Waterfall)

这篇具有很好参考价值的文章主要介绍了Vue3瀑布流(Waterfall)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Vue2瀑布流(Waterfall) 

瀑布流_百度百科

可自定义设置以下属性:

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

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

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

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

  • 瀑布流区域和图片圆角(borderRadius),类型:number,单位px,默认 8

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

效果如下图:在线预览

Vue3瀑布流(Waterfall)

Vue3瀑布流(Waterfall) 其中引用组件:Vue3加载中(Spin)

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

<script setup lang="ts">
import { ref, shallowRef, computed, watch, watchPostEffect } from 'vue'
import Spin from '../spin'
/*
  宽度固定,图片等比例缩放;使用JS获取每张图片宽度和高度,结合 `relative` 和 `absolute` 定位
  计算每个图片的位置 `top`,`left`,保证每张新的图片都追加在当前高度最小的那列末尾
*/
interface Image {
  src: string // 图片地址
  title?: string // 图片名称
}
interface Props {
  images: Image[] // 图片数组
  columnCount?: number // 要划分的列数
  columnGap?: number // 各列之间的间隙,单位px
  width?: string|number // 瀑布流区域的总宽度
  borderRadius?: number // 瀑布流区域和图片圆角,单位px
  backgroundColor?: string // 瀑布流区域背景填充色
}
const props = withDefaults(defineProps<Props>(), {
  images: () => [],
  columnCount: 3,
  columnGap: 20,
  width: '100%',
  borderRadius: 8,
  backgroundColor: '#F2F4F8'
})
const imagesProperty = ref<any[]>([])
const preColumnHeight = ref<number[]>(Array(props.columnCount).fill(0)) // 每列的高度
const waterfall = shallowRef() // ref() 的浅层作用形式
const imageWidth = ref()
const totalWidth = computed(() => {
  if (typeof props.width === 'number') {
    return props.width + 'px'
  } else {
    return props.width
  }
})
const height = computed(() => {
  return Math.max(...preColumnHeight.value) + props.columnGap
})
const len = computed(() => {
  return props.images.length
})
const loaded = ref(Array(len.value)) // 图片是否加载完成
const rerender = ref(false)
watch(
  () => [props.columnCount, props.columnGap, props.width],
  () => {
    rerender.value = true
    preColumnHeight.value = Array(props.columnCount).fill(0)
    onPreload()
  },
  {
    deep: true, // 强制转成深层侦听器
    flush: 'post' // 在侦听器回调中访问被 Vue 更新之后的 DOM
  }
)
watchPostEffect(() => {
  if (props.images.length) {
    onPreload()
  }
})
async function onPreload () { // 计算图片宽高和位置(top,left)
  // 计算每列的图片宽度
  imageWidth.value = (waterfall.value.offsetWidth - (props.columnCount + 1) * props.columnGap) / props.columnCount
  imagesProperty.value.splice(0)
  for (let i = 0; i < len.value; i++) {
    await loadImage(props.images[i].src, i)
  }
}
function loadImage (url: string, n: number) {
  return new Promise((resolve) => {
    const image = new Image()
    image.src = url
    image.onload = function () { // 图片加载完成时执行,此时可通过image.width和image.height获取到图片原始宽高
      if (!rerender.value) {
        loaded.value[n] = false
      }
      var height = image.height / (image.width / imageWidth.value)
      imagesProperty.value[n] = { // 存储图片宽高和位置信息
        width: imageWidth.value,
        height: height,
        ...getPosition(n, height)
      }
      resolve('load')
    }
  })
}
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)
    let index = 0
    for (let n = 0; n < props.columnCount; 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 onLoaded (index: number) {
  loaded.value[index] = true
}
</script>
<template>
  <div class="m-waterfall" ref="waterfall" :style="`--borderRadius: ${borderRadius}px; background-color: ${backgroundColor}; width: ${totalWidth}; height: ${height}px;`">
    <Spin
      v-show="loaded[index]!==undefined"
      class="m-image"
      :style="`width: ${property.width}px; height: ${property.height}px; top: ${property && property.top}px; left: ${property && property.left}px;`"
      :spinning="!loaded[index]"
      size="small"
      indicator="dynamic-circle"
      v-for="(property, index) in imagesProperty" :key="index">
      <img
        class="u-image"
        :src="images[index].src"
        :alt="images[index].title"
        @load="onLoaded(index)" />
    </Spin>
  </div>
</template>
<style lang="less" scoped>
.m-waterfall {
  position: relative;
  border-radius: var(--borderRadius);
  .m-image {
    position: absolute;
    .u-image {
      width: 100%;
      height: 100%;
      border-radius: var(--borderRadius);
      display: inline-block;
      vertical-align: bottom;
    }
  }
}
</style>

②在要使用的页面引入: 文章来源地址https://www.toymoban.com/news/detail-421103.html

<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}`,
      link: '',
      src: `https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.5/${i}.jpg`
    })
  }
}
onBeforeMount(() => { // 组件已完成响应式状态设置,但未创建DOM节点
  loadImages()
})
</script>
<template>
  <div>
    <h1>Waterfall 瀑布流</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Waterfall :images="images" :width="1100" />
    <h2 class="mt30 mb10">自定义展示</h2>
    <Waterfall
      :images="images"
      :width="1100"
      :column-count="4"
      :column-gap="10"
      background-color="#e1faeb"
      :border-radius="6" />
  </div>
</template>

到了这里,关于Vue3瀑布流(Waterfall)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3使用vue-masonry插件实现瀑布流

    《Vue插件》瀑布流插件vue-masonry的使用与踩坑记录 参数: item-selector transition-duration column-width origin-left origin-top gutter 前言: 之前其实有分享过一篇纯CSS实现瀑布流的方法: https://oliver.blog.csdn.net/article/details/126450691,但纯CSS实现的方案都不是比较好的方案,总归有一些各式各样的

    2024年01月19日
    浏览(38)
  • 记录--Vue3基于Grid布局简单实现一个瀑布流组件

    在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,在刷某书和某宝首页时,我们发现其展示方式就是一种瀑布流,是一种流行的网站页面布局,视觉表现为参差不齐的多栏布局,随着页

    2024年02月05日
    浏览(66)
  • 维基百科、百度百科和搜狗百科词条的创建流程

    随着网络的发展,百度百科、搜狗百科、维基百科等百科网站已经成为大众获取知识的重要途径。因为百科具有得天独厚的平台优势,百科上的信息可信度高,权威性强。所以百科平台也成为商家的必争之地。这里小马识途聊聊如何创建百度百科、搜狗百科和维基百科词条。

    2024年04月27日
    浏览(45)
  • 百度百科词条怎么更新?怎么能顺利更新百科词条?

    企业和个人百度百科词条的更新对于他们来说都具有重要的意义,具体如下: 对企业来说: 塑造品牌形象:百度百科是一个常被用户信任并参考的知识平台,通过更新企业词条可以提供准确、全面的企业信息,帮助企业塑造积极的品牌形象。 增加曝光和知名度:百度百科在

    2024年02月10日
    浏览(45)
  • 创建维基WIKI百科和建立百度百科有何不同?

    很多企业有出口业务,想在互联网上开展全球性网络营销,维基百科往往被认为是开展海外营销的第一站。其作用相当于开展国内网络营销的百度百科,经常有些企业给小马识途营销顾问提供的词条内容就是百度百科的内容,可事实上两个平台的规则差异很大,在百度百科上

    2024年02月15日
    浏览(53)
  • 如何给自己创建个人百度百科词条,人物百科词条审核通过技巧

    想要让自己在百度上能够搜索得到,一般都需要给自己创建一个个人百度百科词条,但很多人发觉自己创建人物百度百科词条怎么审核也审核不过,其实主要还是百科词条文案和个人百科词条参考资料的问题。下面洛希爱做百科网分享如何给自己创建个人百度百科词条,人物

    2023年04月20日
    浏览(51)
  • 创建个人百度百科需要什么条件?

    互联网时代,创建百度百科词条可以给个人带来更多的曝光和展现,相当于一个镀金的网络名片,人人都想上百度百科,但并不是人人都能创建上去的。 个人百度百科词条的创建需要满足一定的条件,今天 伯乐网络传媒 就来给大家聊聊这个话题,看你到底能不能上百度百科

    2024年04月16日
    浏览(44)
  • 公司创建百度百科需要哪些内容?

    一个公司或是一个品牌想要让自己更有身份,更有知名度,更有含金量,百度百科词条是必不可少的。通过百度百科展示公司的详细信息,有助于增强用户对公司的信任感,提高企业形象。通过百度百科展示公司的发展历程、领导团队、企业荣誉等,可以彰显公司的实力和行

    2024年02月03日
    浏览(39)
  • 创建一个简易百度百科词条的方法!

    百度百科作为中国最大的中文百科全书,拥有着广泛的用户群体和权威性。对于许多人来说,创建一个百度百科词条是一种展示自己和宣传自己的有效方式。所以越来越多的人都想要上百度百科,百度百科词条的创建是一大难关,今天伯乐网络传媒就来给大家分享创建一个简

    2024年02月21日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包