基于vue的固定高度图片瀑布流组件

基于vue的固定高度图片瀑布流组件

<!-- 
 @Description: pictureList 图库列表组件
 @Author: sunyongwei
 @Date: 2022-10-12
 @Version: V1.0
 -->
<template>
  <div style="margin: 20px;">
   <div style="display: flex;justify-content: space-between">
      <div style="min-width: 20%;">
        <div style="font-weight: bold;font-size: 16px;">
          <span v-for="(item,index) in fullTitle">{{item}}
             <span v-if="index<fullTitle.length-1">/ </span>
          </span>
        </div>
        <div style="font-size: 10px;color: #767676;">{{list.length}}个文件,共{{(sizeTotle / 1024 / 1024).toFixed(3)}}GB</div>
      </div> 
      <div>
      </div>     
   </div>
   <div v-if="rowList.length>0">
        <div class="row" v-for="(row,index) in rowList" :key="index" style="min-width:1100px;">
             <div class="img-box" v-for="img in row" :key="img.id" :style="{'width':img.width+'px','height':img.height+'px','margin':'0 '+ imgMargin+'px'}">
                <img :src="img.url"  :style="{'width':img.width+'px','height':img.height+'px'}" v-if="img.type == '1'"></img>
                <img :src="img.cover"  :style="{'width':img.width+'px','height':img.height+'px'}" v-if="img.type == '2'"></img>
            </a>
          </div>
        </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'pictureList',
    props:{
      list:{ //图片列表
        type:Array,
        default() {
          return []
        }
      },
      fullTitle:{ //全节点名称
        type:Array,
        default() {
          return ''
        }
      },
      imgHeight: { //固定宽度
        type: Number,
        default: 220
      },
      imgMargin: { //margin间距
        type: Number,
        default: 5
      },
      button: { //按钮显示状态
        type: Boolean,
        default: true
      },
    },
    data () {
      return {
        pictureList:[], 
        screenWidth:1000,
        sizeTotle:0
      }
    },
    watch:{
      list(){
        this.sizeTotle = 0
        this.initList()
        if(this.list.length==0)return
        this.list.forEach(e=>{
          this.sizeTotle += e.size
        })
      },
    },
    computed: {
      rowList () {
        return this.waterfallHandler()
      }
    },
    mounted() {
      this.screenWidth = document.body.clientWidth;
      window.onresize = () => {
        return (() => {
          this.screenWidth = document.body.clientWidth;
          this.waterfallHandler()
        })();
      };
      let that = this
      setTimeout(function(){
        that.screenWidth = document.body.clientWidth-1;
        that.waterfallHandler()
      },500)
    },
    created() {
      if(this.list.length==0)return
      this.initList()
      this.list.forEach(e=>{
        this.sizeTotle += e.size
      })
    },
    methods: {
      initList(){
        this.pictureList = []
        if(this.list.length==0)return
        this.list.forEach(e=>{
            let item = e
            var img = new Image();
            img.src = e.type == '1' ? item.url : item.cover;
            img.onload = function(){
              item.width = img.width
              item.height = img.height
            } 
            this.pictureList.push(item)
        })
      },
      onChange(){
        this.$emit('onChange')
      },
       waterfallHandler() {
         if(this.list.length==0)return []
         const newList = []
         // 设定一个浏览器宽度的最低值为1000px
         const screenWidth = Number(this.screenWidth) > 1000 ? Number(this.screenWidth) - 500 : 1000
         // 先把设定的基础高度当作行高
         const rowHeight = this.imgHeight
         let arrRow = []
         let imgsData = []
         // 深拷贝转储一下
         imgsData = JSON.parse(JSON.stringify(this.pictureList))
         // 循环 计算每个图片的宽度
         for (let i = 0; i < imgsData.length; i++) {
           const item = imgsData[i]
           // 计算图片的宽高比
           item.ratio = Number(item.width) / Number(item.height)
           // 新的宽度,算法是比例乘以行高
           const newWidth = parseInt(item.ratio * rowHeight)
           item.width = newWidth
           item.height = rowHeight
           // 定义该行图片宽度之和
           let totalWidth = 0
           arrRow.push(item)
           for (let i = 0; i < arrRow.length; i++) {
             totalWidth += arrRow[i].width
           }
           // 如果该行加入的图片宽度大于了该行的宽度
           // 就需要弹出最后一张图片,并更改前面的图片大小比例
           if (totalWidth > screenWidth) {
             // 把最后一张弹出,恢复原来的wholeWidth
             const lastImg = arrRow.pop()
             totalWidth -= lastImg.width
             // 利用面积相等原则,来计算新的高度
             const newHeight = screenWidth * rowHeight / totalWidth
             // 这里是根据一行图片的数量,计算需要留出的边距
             const marginSpace = (arrRow.length - 1) * (this.imgMargin / 20)
             // 重新计算宽高,占满一行
             for (let i = 0; i < arrRow.length; i++) {
               // 最后再把每张图片等比例缩小一点,以留出边距
               arrRow[i].width = newHeight * arrRow[i].ratio - marginSpace
               arrRow[i].height = newHeight - (marginSpace / arrRow[i].ratio)
             }
             // 放置完毕之前的图片之后,清空该图片队列
             // 并将上一行溢出的图片 作为下一行的第一张
             newList.push(arrRow)
             arrRow = []
             arrRow.push(lastImg)
           }
         }
         // 单独处理未最后一行
         // 遍历每一行,把每一行的长度都加起来,这样能得出最后一行的元素数量
         let tmp = 0
         for (let i = 0; i < newList.length; i++) {
           tmp += newList[i].length
         }
         const lastRow = []
         for (let i = tmp; i < imgsData.length; i++) {
           // 高度以基础高度为基准
           imgsData[i].height = rowHeight
           // 宽度也是按照比例计算
           imgsData[i].width = imgsData[i].ratio * rowHeight
           lastRow.push(imgsData[i])
         }
         newList.push(lastRow)
         return newList
       }
    }
  }
</script>

<style scoped >
  
   
   .popover-button{
     line-height: 40px;
     padding:0 20px;
     color: #000;
     border-bottom: 1px solid #D8D8D8;
   }
   .popover-button:hover{
     cursor: pointer;
     color: #1890FF;
     border-bottom: 1px solid #1890FF;
   }
   
   .row {
     margin-top: 5px;
     display: flex;
   }
   
   a {
     text-align: center;
   }
   
   .img-box {
     transition: all 0.5s;
   }
   
   .img-box>img {
     transition: all 0.5s;
   }
   
   .img-box:hover {
     transform: scale(1.05);
   }
   
   .img-box:hover>img {
     transform: scale(1.05);
   }
  
</style>

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巧克力味。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值