ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue实现瀑布流

2021-12-18 14:31:57  阅读:206  来源: 互联网

标签:arr vue console 实现 items px style 瀑布 var


        本文中所采用的纯css实现瀑布流的效果并不是很好分析如下(个人见解,可能会有错误,请见谅):

        1.如果要实现下拉加载更多功能的话就不能用视频(https://www.bilibili.com/video/BV1xa4y147JP)中的第二种方法。虽然第二种方法可以实现图像的横向排序(第一行显示序号为0~n),但是需要固定距离,我觉得用这个方法的话有所限制,也可能我理解不够,见谅哈。
        2.过要实现图片的横向排序的话,就不能用视频(https://www.bilibili.com/video/BV1xa4y147JP)中的第一种方法,因为第一种方法图像时纵向排序的(第一列为0~n,第二列为n+1~2n,......)。这样对之后上传新的图片不是很友好,因为新的始终是在第一列或者最后一列,按常理来讲,新图片应该是放在第一行最好。

        最后我采用的是js实现瀑布流(这玩意确实是顶级折磨)。参考链接为"https://segmentfault.com/a/1190000012621936"(这个很重要)。中心思想:1.预先设定好要多少列(这里是更具我自己需求来的)2.排列第一行,动态设置每个盒子的left就可以排列好3.排列好第一行后,获取第一行盒子的高度,并且存到一个数组arr中,因为第二行的排列只需要考虑top值(这里可以适当加一个值,让上下两张图片有间隙)4.排列第二行,以此类推。详细的可以看那位作者的文章(上面的连接),里面的说明更加具体。5.在mounted中进行监听,以便随着窗口的改变,里面的item也跟着改变。 

         我用的是vue2,据说是要避免直接操作dom(我也还没遇到直接操作导致的bug),我用的是ref来操作的,相关代码贴图如下(我自己写的网站还不知道怎么实现贴代码,且不打乱格式,见谅哈)

实验结果 

 

代码部分

 html代码

    <div class="picList">
      <div class="masonry" ref="pictest">
        <div class="item" v-for="(picture,index) in piclist" :key="index">
          <!-- 删掉一个ifload@load="ifLoad" -->
          <!--判断图片是否加载好-->
          <img :src="picture.pic" :alt="index" @click="showBigPic(index)" class="picture" @load="ifLoad">
          <el-dialog
            title="大图"
            :visible.sync="centerDialogVisible"
            width="50%"
            center>
            <img :src="bigPic" alt="" style="width:96%">
            <span slot="footer" class="dialog-footer">
              <el-button @click="centerDialogVisible = false">取 消</el-button>
              <el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
            </span>
          </el-dialog>
          <div class="picName">{{picture.name}}</div>
          <div class="icon">
            <!-- 点赞 -->
            <i class="iconfont like" :ref="'picLike'+index" @click="like(index)">&#xe622;</i>
            <!-- 收藏 -->
            <i class="iconfont collect" :ref="'picCollect'+index" @click="collect(index)">&#xe616;</i>
            <!-- 评论可以不用变色  <i class="iconfont comment" :ref="'picComment'+index" @click="comment(index)">&#xe615;</i> -->
            <i class="iconfont comment">&#xe615;</i>
          </div>
        </div>
      </div>
    </div>

css代码

  .picList{
    padding: 20px; // 这个会导致this.$refs.pictest.clientWidth多20
    width: 95%;
    margin: 0px auto;
    box-sizing: border-box;
    list-style: none;
    background-color: #fff;
    border-radius: 10px;
    .masonry{
      // float: left;
      position: relative;
      overflow: hidden;
      border-radius: 10px;
      margin: 0;
      background-color: rgb(233, 233, 233);
      .item{
        // float: left;
        position: absolute;
        max-width: 260px; // 设置最大的width,避免loadmore时太大影响观感
        background-color: #fff;
        border-radius: 10px;
        img{
          display: block;
          text-align: center;
          width: 95%;
          // height: auto;
          border-radius: 10px;
          margin: 10px auto;
          cursor: pointer;
        }
        .picName{
          padding-left: 10px;
          padding-bottom: 5px;
        }

js代码

        data部分

  data() {
    return {
      scrollHeight: 0, // 滚动的高度
      itemWidth: 0 + 'px', // 每个item 的宽度
      showPicList: [], // 获取全部图片的src
      piclist: [], // 获取showPicList中部分图片进行显示,之后再从loadmore()中获取更多(下拉加载功能)
      bigPic: '',
      centerDialogVisible: false,
      loadCount: 0
      // width: this.$refs.pictest.clientWidth
    }
  },

        methods部分 

    waterfall() {
      var items = this.$refs.pictest.children
      // var itemWidth = 270
      var columns1 = 4
      var arr = []
      // 距离左右边缘的距离固定,item的缝隙固定
      var gapToTop = 10 // 与顶部之间的距离,避免盒子重合
      var gap = 20 // 上下间距
      var gapBetween = 10 // 左右item之间的距离
      var gapToSide = 10 // 到masonry左、右边缘的距离
      // var calcItemWidth = (this.$refs.pictest.clientWidth - 2 * gapToSide - (columns1 - 1) * gapBetween) / 4
      console.log(this.$refs.pictest.clientWidth)
      // 实现左右对称
      // items[0].style.left = gapToSide + 'px'
      // items[columns1 - 1].style.right = gapToSide + 'px'
      var calcItemWidth = (this.$refs.pictest.clientWidth - 2 * gapToSide - (columns1 - 1) * gapBetween) / 4
      this.itemWidth = calcItemWidth + 'px'
      for (var i = 0; i < items.length; i++) {
        this.$refs.pictest.children[i].style.width = calcItemWidth + 'px'
        console.log(calcItemWidth)
        // console.log(items[i].offsetHeight, items[i].clientHeight, items[i].offsetWidth, items[i].clientWidth)
        if (i < columns1) {
          items[i].style.top = gapToTop + 'px'
          // 调节第一行偏移量,让整个瀑布流区域居中
          // items[i].style.left = (calcItemWidth + gapBetween) * i + gapToSide + 'px'
          items[i].style.left = (calcItemWidth + gapBetween) * i + gapToSide + 'px'
          // console.log(items[i].style.top)
          arr.push(items[i].offsetHeight + gap)
          // console.log(items[i].offsetHeight)
        } else {
          var minHeight = arr[0]
          var index = 0
          for (var j = 0; j < arr.length; j++) {
            if (minHeight > arr[j]) {
              minHeight = arr[j]
              index = j
            }
          }
          items[i].style.top = arr[index] + gapToTop + 'px'
          // console.log(arr[0])
          items[i].style.left = items[index].offsetLeft + 'px'
          arr[index] = arr[index] + items[i].offsetHeight + gap
        }
      }
      // console.log(Math.max(...arr))
      this.$refs.pictest.style.height = Math.max(...arr) + 25 + 'px'
    },
    // 等图片加载完后执行瀑布流函数
    ifLoad() {
      this.loadCount++
      if (this.loadCount === this.$refs.pictest.children.length) {
        console.log(this.loadCount)
        this.waterfall()
      }
    },
    // 下拉加载更多
    loadMore() {
      var piclistlen = this.piclist.length
      var showPicListlen = this.showPicList.length
      if (showPicListlen - piclistlen >= 4) {
        this.piclist.push(...(this.showPicList.slice(piclistlen, piclistlen + 4)))
        // this.$refs.pictest.children.map(child => { child.style.width = that.itemWidth })
      } else {
        this.piclist.push(...(this.showPicList.slice(piclistlen, showPicListlen)))
      }
    },

         mounted部分

  mounted() {
    // console.log(document.getElementsByClassName('masonry'))
    window.addEventListener('resize', () => {
      this.waterfall()
    })
    window.addEventListener('scroll', () => {
      console.log(window.scrollY)
      var that = this
      if (window.scrollY > that.scrollHeight) {
        if (window.scrollY - that.scrollHeight >= 100) {
          this.loadMore()
          this.scrollHeight = window.scrollY
        }
      }
    })
  },

补充说明

  没有图片素材的同学可以尝试一下下面提到的这个网址,加到img的src就可以了(https://picsum.photos/360/400)  第一个参数360是指图片宽度,第二个参数400是指图片高度,每次都是会随机显示不同图片的,可以用代码把这些src放到一个arr里面,然后v-for循环显示。例子如下:

    for (let i = 0; i <= 19; i++) {
      const height = Math.floor((Math.random() * 200) + 201)
      this.piclist.push('https://picsum.photos/360/' + height + '?random=' + (i + 1))
    }

参考连接

https://www.bilibili.com/video/BV1xa4y147JP

https://segmentfault.com/a/1190000012621936(多看这个,这个很重要)

标签:arr,vue,console,实现,items,px,style,瀑布,var
来源: https://blog.csdn.net/wenguangze/article/details/122011400

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有