Vue 原生瀑布流图片

版权声明:来自MarieDreamer https://blog.csdn.net/qq_33514421/article/details/82995701

效果

  

 思路

1、html中建立四个“管道”

2、后台获取到数据

3、遍历数据,获取高度最小的管道,填入数据

4、滚动条到底时触发函数,获取下一页数据,然后再执行步骤3

参考

jquery实现滑动到底部加载下一页的数据

代码

template:建立四个piping,ref参数是为了在js中获取dom元素。

<template>
    <div class="friend_moments">
      <div class="water">
        <div class="piping" ref="piping0">
        </div>
        <div class="piping" ref="piping1">
        </div>
        <div class="piping" ref="piping2">
        </div>
        <div class="piping" ref="piping3">
        </div>
      </div>
    </div>
</template>

 script:

export default {
  data() {
    return {
      moments: [],
      available: 1,
      height1: 0,
      height2: 0,
      height3: 0,
      page: 1
    };
  },
  created() {
    // 获取第一页数据
    this.fetchMoments();
  },
  mounted() {
    // 用来监听滚轮
    window.addEventListener("scroll", this.handleScroll);
  },
  methods: {
    fetchMoments() {
      // 请求接口方法
      fetch("api/moments")
        .then(res => res.json())
        .then(res => {
          this.moments = res.data;
          // 分配数据到指定管道
          this.sort(0);
        });
    },
    // sort()函数是递归的,因为要确保每个卡片的图片加载完成后再获取管道的高度,但是图片加载完成的函数是个异步函数,
    // 如果放在for循环中会打乱顺序,因此要使异步函数同步执行,for循环改为递归。
    sort(j) {
      if (j < this.moments.length) {
        let that = this;
        // 创建Image类
        var newImg = new Image();
        // 获取要加载的图片地址
        newImg.src =
          "http://lanyue.ink:8123/images/" +
          (Math.floor(Math.random() * 15) + 1) +
          ".png";
        // 图片加载完成后(异步)
        newImg.onload = () => {
          // 四个管道的高度 
          var arr = [
            that.$refs.piping0.offsetHeight,
            that.$refs.piping1.offsetHeight,
            that.$refs.piping2.offsetHeight,
            that.$refs.piping3.offsetHeight
          ];
          //获取管道最小高度
          var min = arr.indexOf(Math.min.apply(Math, arr));
          // 添加卡片的模板
          var html =
            `<div class="card">
                <img src=` + newImg.src + `>
                <div>
                  <img src="http://lanyue.ink:8123/images/avatar.jpg" alt="">
                  <div>` + this.moments[j].id + "  " + this.moments[j].content + `</div>
                </div>
            </div>`;
          //给最小的管道添加卡片
          if (min == 0) {
            that.$refs.piping0.innerHTML += html;
          } else if (min == 1) {
            that.$refs.piping1.innerHTML += html;
          } else if (min == 2) {
            that.$refs.piping2.innerHTML += html;
          } else if (min == 3) {
            that.$refs.piping3.innerHTML += html;
          }
          that.sort(j + 1);
        };
      }
    },
    handleScroll() {
      // 获取滚轮位置
      var scrollTop =
        window.pageYOffset ||
        document.documentElement.scrollTop ||
        document.body.scrollTop;
      this.height1 = scrollTop;
      // 文档高度
      this.height2 = document.body.scrollHeight;
      // 可视区域
      this.height3 =
        document.compatMode == "CSS1Compat"
          ? document.documentElement.clientHeight
          : document.body.clientHeight;
      // 如果滚动到最低(这里设置离最底还有100距离才触发函数)
      // available条件是为了防止触底时一直不断地请求。因此,请求一次后available设为0,直到滚动到离底部超过100距离(即数据加载玩后)才设为1
      if (this.height3 + this.height1 >= this.height2 - 100 && this.available) {
        //请求下一页
        this.page++;
        this.available = 0;
        let that = this;
        fetch("api/moments?page=" + this.page)
          .then(res => res.json())
          .then(res => {
            that.moments = res.data;
            if (that.moments[0]) {
              that.sort(0);
            } else {
              that.page--;
            }
          });
      } else if (this.height3 + this.height1 < this.height2 - 100) {
        this.available = 1;
      }
    }
  }
};

scss:

<style lang="scss">
.friend_moments {
  width: 100%;
  display: flex;
  justify-content: center;
}
.a {
  position: fixed;
  width: 200px;
  top: 200px;
  right: 100px;
  z-index: 10;
  background: #eee;
}
.water {
  width: 1240px;
  margin-top: 60px;
  display: flex;
  align-items: flex-start;
  margin-bottom: 100px;
  .piping {
    width: 25%;
    padding: 10px;
    padding-bottom: 0px;
  }
}
.card {
  width: 290px;
  border-radius: 5px;
  box-shadow: 0px 0px 5px #888888;
  margin-bottom: 20px;
  > img:first-child {
    width: 100%;
    border-radius: 5px;
  }
  > div:nth-child(2) {
    display: flex;
    align-items: center;
    padding: 10px;
    > img {
      border-radius: 100%;
      width: 32px;
      height: 32px;
      margin-right: 10px;
    }
  }
}
</style>

扩展

如果希望图片框大小一样,则设置图片为背景图片,cover居中显示。

1、就把scss中的card类改为:

.card {
  width: 290px;
  border-radius: 5px;
  box-shadow: 0px 0px 5px #888888;
  margin-bottom: 20px;
  > div:first-child {
    width: 100%;
    height: 200px;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    border-radius: 5px;
  }
  > div:nth-child(2) {
    display: flex;
    align-items: center;
    padding: 10px;
    > img {
      border-radius: 100%;
      width: 32px;
      height: 32px;
      margin-right: 10px;
    }
  }
}

2、把script中html模板改成:

var html =
    `<div class="card">
        <div style=background-image:url(` + newImg.src + `)></div>
        <div>
            <img src="http://lanyue.ink:8123/images/avatar.jpg" alt="">
            <div>` + this.moments[j].id + "  " + this.moments[j].content + `</div>
        </div>
    </div>`;

修改后的效果:

这样,高度的差别就主要来自卡片的底部内容高度。

猜你喜欢

转载自blog.csdn.net/qq_33514421/article/details/82995701