vue实现瀑布流+下拉加载更多

<template>
  <div ref="waterfallFlow" class="waterfallFlow-wrapper" :style="{height:Math.max(...columns)+'px'}">
    <div v-for="(item,index) in list" :style="{width:width+'px',transform:`translate(${item.x+'px'},${item.y+'px'})`}"
         class="waterfallFlow-item" :key="item.url+index">

      <img v-if="item.renderHeight" :style="{display: 'block',width: '100%'}" :src="item.url" alt="">
    </div>
  </div>
</template>
<script>
export default {
  name: 'waterfallFlow',
  data() {
    return {
      columns: [],
      columnNums: 0,
      width: 260,
      loadMore: false,
      list: [
        {
          url: 'https://photo.colorhub.me/7ctMvIy5wTY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjYvNzYvOTYzM2VjZjI5ODk5MDVmMDg4NDE4MGRjZTVhNjdmZTljMDYxZjY3Ni5qcGVn.webp',
          x: 0,
          y: 0
        },

        {
          url: 'https://img.colorhub.me/5tNgQlTNeGU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMDUvNGYvYzA4MTA1Yzc3ZWEwOWU1N2IzZTg1NTRlNGNiMTZlMDAxYTY5MDU0Zi5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/64ilh6vc2tw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOWYvODgvNmZiZmM3YWU5OWIwYmQyNzZmMWM5MWMwMWRiODAxNzU3YzkxOWY4OC5qcGc.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/0pxXm7FwgQU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzIvZWIvMGQ0Y2ZiNzkzMjlmNDI0ZTJlY2U4YTI1MjZkY2Q3ZjZiOGQ4MzJlYi5qcGc.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/5HEmB2Et7lw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNDIvNzUvN2M3MjdmYzFiZDNmN2FhZmFkYzQ5Y2E5MjQ3ZGRjOGEzMzI3NDI3NS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/Tlr2i3HcNYY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvMDkvYmZkYzc3MTk4ZTE1Mjg2ZjVmNTI0OWMwZjNkZjY4YWE4OGZlN2MwOS5qcGVn.webp',
          x: 0,
          y: 0
        },

        {
          url: 'https://cdn.colorhub.me/31EWPPaC3rM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjQvMDUvYzZhMDU1NTdkZDE2NDdiZjJlNzYyNzkzM2U1OWM1OWVjZTFmMjQwNS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/ojwHoKOthec/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNmYvNjMvOGJjODJjNjNmMzYyM2M4MWI1NzkwYWY1MWE3Y2Y0YmNhYTAzNmY2My5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/G3S8lTFEJIQ/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOGYvMGEvMTlmZjkyNjg1YTMxZDM0MzVjMDdhMGFiMzBhOGU5MzI1YzdlOGYwYS5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://photo.colorhub.me/sYVTa7sM6G4/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWQvNDkvMmRiZTFlYmJjODc4MDg3OTIzZTE4MDQxMjg0MmQ3OGVkOTc1MWQ0OS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://photo.colorhub.me/v-a0VjH_zy8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTAvNmYvMTVjMTc0MzgzMzllMTg2OGRiOWEzZTQxMDRiZjcwMjM4Y2Q1OTA2Zi5qcGVn.webp',
          x: 0,
          y: 0
        },

        {
          url: 'https://img.colorhub.me/qaEWeUC5c9c/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvNWQvZjliOTc1YjFjMWI4NmE4MDhiYTYxNjhhM2JmM2UxOTEzMTgyN2M1ZC5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://photo.colorhub.me/1ejmPjby2d0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vY2UvNTcvM2Q4Mzg0YTQ3MGU4NzZlNTViNDg0ODFmYzUxYzM1MDU0NTk5Y2U1Ny5qcGc.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://photo.colorhub.me/7AOB0NAaR0M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzAvYWYvNzE1MjNmYTRkYTg3MDUwNzZmNWEwMGQ5ZDU1NTY4NWNhZGVjNzBhZi5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/Qf2HhLXPads/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzYvNzMvNWYwZjkyNDczNWVjZjM1NmIxNjllMzE5ZTI5NGZmN2Q4ZDQyNzY3My5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/_4JZX-83nJ8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjgvZWYvMjUxMjQ4NjYzZDIzYmJhZmRlN2ViZTEwZTgzZDA5ZDA5ZWJiZjhlZi5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/uEfq-MyTM2o/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYzYvOTcvMjJmZDQ3NDdhMTljZTI0NjJjNjQ2Y2ZhY2YyMGZiY2ZhMTUxYzY5Ny5qcGc.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/B4oQ_z1BvJc/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTkvNGYvMTA4ZGNlYmVlYWU1YWEyZGVlNzJmNzk5NjgwODAxYTkxZDY0OTk0Zi5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/8gK5WgsJi_0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjUvNTIvOWFmOWM4Yjg3ZWMxZmU5ODg3Y2UyNzQ3MTQ1NjY0YTNiNWRiMjU1Mi5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/DAWB9Jj1Ais/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYjUvZmUvODNlZGY0OTNhZmVhZTRlY2M1OGQ1MDY0YWQzYzJhYzNkYjM2YjVmZS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/81plMyBlfqk/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzUvMjMvZTg4MzJlZmE3MTFiMWE4M2I3M2VmOWU5YzIyNzFmODAxZDVkNzUyMy5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/lDLUT-mvKks/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZWMvNjkvY2NmMDlkZTc1ZTM3MzMxYTdkNTVhMDZkYjY3MDQxNjY0Y2FkZWM2OS5qcGVn.webp',
          x: 0,
          y: 0
        },


      ],
      dropDownData: [
        {
          url: 'https://photo.colorhub.me/4khg6amuZ9M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzUvN2QvMjdhYjA2MmQzOGJjNmQwZDZmYTY0ZmQ3M2JmMTA5NzdjYjNhMzU3ZC5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://photo.colorhub.me/s4HBOYxWq90/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMmEvYWMvMmYyNWJlNWI0YmY5MzM5YzhiOWNkOGM2NzkxMzkwODJhMDFlMmFhYy5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/uv4uJAItejI/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMDMvMTgvYWMwMDg1ODdhYTEzZDViNjI1OTA2OGJhOTg3MDNmNjc2MTMwMDMxOC5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/0pxXm7FwgQU/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMzIvZWIvMGQ0Y2ZiNzkzMjlmNDI0ZTJlY2U4YTI1MjZkY2Q3ZjZiOGQ4MzJlYi5qcGc.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/5HEmB2Et7lw/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNDIvNzUvN2M3MjdmYzFiZDNmN2FhZmFkYzQ5Y2E5MjQ3ZGRjOGEzMzI3NDI3NS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/Tlr2i3HcNYY/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvMDkvYmZkYzc3MTk4ZTE1Mjg2ZjVmNTI0OWMwZjNkZjY4YWE4OGZlN2MwOS5qcGVn.webp',
          x: 0,
          y: 0
        },

        {
          url: 'https://cdn.colorhub.me/31EWPPaC3rM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjQvMDUvYzZhMDU1NTdkZDE2NDdiZjJlNzYyNzkzM2U1OWM1OWVjZTFmMjQwNS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/ojwHoKOthec/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNmYvNjMvOGJjODJjNjNmMzYyM2M4MWI1NzkwYWY1MWE3Y2Y0YmNhYTAzNmY2My5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/G3S8lTFEJIQ/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOGYvMGEvMTlmZjkyNjg1YTMxZDM0MzVjMDdhMGFiMzBhOGU5MzI1YzdlOGYwYS5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://photo.colorhub.me/sYVTa7sM6G4/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWQvNDkvMmRiZTFlYmJjODc4MDg3OTIzZTE4MDQxMjg0MmQ3OGVkOTc1MWQ0OS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://photo.colorhub.me/v-a0VjH_zy8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vOTAvNmYvMTVjMTc0MzgzMzllMTg2OGRiOWEzZTQxMDRiZjcwMjM4Y2Q1OTA2Zi5qcGVn.webp',
          x: 0,
          y: 0
        },

        {
          url: 'https://img.colorhub.me/qaEWeUC5c9c/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vN2MvNWQvZjliOTc1YjFjMWI4NmE4MDhiYTYxNjhhM2JmM2UxOTEzMTgyN2M1ZC5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://photo.colorhub.me/1ejmPjby2d0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vY2UvNTcvM2Q4Mzg0YTQ3MGU4NzZlNTViNDg0ODFmYzUxYzM1MDU0NTk5Y2U1Ny5qcGc.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://photo.colorhub.me/7AOB0NAaR0M/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzAvYWYvNzE1MjNmYTRkYTg3MDUwNzZmNWEwMGQ5ZDU1NTY4NWNhZGVjNzBhZi5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/Qf2HhLXPads/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzYvNzMvNWYwZjkyNDczNWVjZjM1NmIxNjllMzE5ZTI5NGZmN2Q4ZDQyNzY3My5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/_4JZX-83nJ8/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZjgvZWYvMjUxMjQ4NjYzZDIzYmJhZmRlN2ViZTEwZTgzZDA5ZDA5ZWJiZjhlZi5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/uEfq-MyTM2o/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYzYvOTcvMjJmZDQ3NDdhMTljZTI0NjJjNjQ2Y2ZhY2YyMGZiY2ZhMTUxYzY5Ny5qcGc.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://cdn.colorhub.me/luBXTEKH8FM/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMWEvNGEvMDc3Mjk3MjEyNzUxYmJkNTZjZTE3MTk1YWIwYTlmOWRiYWFmMWE0YS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/8gK5WgsJi_0/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vMjUvNTIvOWFmOWM4Yjg3ZWMxZmU5ODg3Y2UyNzQ3MTQ1NjY0YTNiNWRiMjU1Mi5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/DAWB9Jj1Ais/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vYjUvZmUvODNlZGY0OTNhZmVhZTRlY2M1OGQ1MDY0YWQzYzJhYzNkYjM2YjVmZS5qcGVn.webp',
          x: 0,
          y: 0
        },
        {
          url: 'https://img.colorhub.me/81plMyBlfqk/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vNzUvMjMvZTg4MzJlZmE3MTFiMWE4M2I3M2VmOWU5YzIyNzFmODAxZDVkNzUyMy5qcGVn.webp',
          x: 0,
          y: 0
        }, {
          url: 'https://cdn.colorhub.me/lDLUT-mvKks/rs:auto:0:500:0/g:ce/fn:colorhub/bG9jYWw6Ly8vZWMvNjkvY2NmMDlkZTc1ZTM3MzMxYTdkNTVhMDZkYjY3MDQxNjY0Y2FkZWM2OS5qcGVn.webp',
          x: 0,
          y: 0
        },

      ],
    }
  },
  async mounted() {
    await this.getColumnNums()
    await this.calcData(this.list)
    window.addEventListener('resize', this.handleResize);
    window.addEventListener('scroll', this.handleScroll);
  },
  beforeDestroy() {
    // 在组件销毁前移除事件监听,避免内存泄漏
    window.removeEventListener('resize', this.handleResize);
    window.removeEventListener('scroll', this.handleScroll);
  },
  methods: {
    //窗口改变重新计算
    async handleResize() {
      await this.getColumnNums()
      await this.newCalc()
    },
    //触底加载更多
    async handleScroll() {
      if (this.loadMore) return
      const scrollTop =
          document.documentElement.scrollTop || document.body.scrollTop;
      const clientHeight =
          document.documentElement.clientHeight || document.body.clientHeight;
      const scrollHeight =
          document.documentElement.scrollHeight || document.body.scrollHeight;
      if (scrollTop + clientHeight + 10 >= scrollHeight) {
        this.loadMore = true
        await this.newAddCalc(this.dropDownData)
      }
    },
    async newAddCalc(list) {
      for (let i = 0; i < list.length; i++) {
        this.list.push(await this.newGetImgInfo(list[i], i))
      }
    },
    newGetImgInfo(item, idx) {
      let that = this
      return new Promise((resolve, reject) => {
        let img = new Image()
        img.src = item.url
        img.onload = function () {
          //渲染后的高度
          let renderHeight = ((that.width - 10) / this.width * this.height) + 10
          let {value, index} = that.findMinItemAndIndex(that.columns)
          item.x = index * that.width


          item.y = value
          that.columns[index] += renderHeight
          item.renderHeight = renderHeight
          resolve(item)
        }
      });
    },
    newCalc() {
      this.list.map((item, idx) => {
        if (idx < this.columnNums) {
          item.y = 0
          item.x = idx * this.width
          this.columns[idx] = item.renderHeight
        } else {
          let {value, index} = this.findMinItemAndIndex(this.columns)
          item.x = index * this.width


          item.y = value
          this.columns[index] += item.renderHeight
        }
      })
    },
    async calcData(list) {
      for (let i = 0; i < list.length; i++) {
        await this.getImgInfo(list[i], i)
      }
    },
    //获取图片的高度
    getImgInfo(item, idx) {
      let that = this
      return new Promise((resolve, reject) => {
        let img = new Image()
        img.src = item.url
        img.onload = function () {
          //渲染后的高度
          let renderHeight = ((that.width - 10) / this.width * this.height) + 10
          if (idx < that.columnNums) {
            item.y = 0
            item.x = idx * that.width
            that.columns[idx] = renderHeight
          } else {
            let {value, index} = that.findMinItemAndIndex(that.columns)
            item.x = index * that.width

            item.y = value
            that.columns[index] += renderHeight
          }
          item.renderHeight = renderHeight
          resolve()
        }
      });
    },
    //获取一共可以展示几列
    getColumnNums() {
      this.$nextTick(() => {
        this.columns = []
        let {width} = this.$refs.waterfallFlow.getBoundingClientRect()
        this.columnNums = ~~Number((width / this.width))
        for (let i = 0; i < this.columnNums; i++) {
          this.columns.push(0)
        }
      })
    },
    //获取数组中最小的那一项和下标
    findMinItemAndIndex(arr) {
      let min = arr[0];
      let minIndex = 0;
      for (let i = 1; i < arr.length; i++) {
        if (arr[i] < min) {
          min = arr[i];
          minIndex = i;
        }
      }
      return {value: min, index: minIndex};
    }
  },
}
</script>

<style lang="scss" scoped>
.waterfallFlow-wrapper {
  position: relative;

  .waterfallFlow-item {
    position: absolute;
    left: 0;
    top: 0;
    padding: 5px;
    box-sizing: border-box;
    transition: .3s linear;
  }
}
</style>

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值