Vue 瀑布流布局+触底加载下一页(原生)

效果

Vue 瀑布流布局+触底加载下一页(原生)_第1张图片

 思路

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

2、后台获取到数据

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

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

参考

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

代码

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

 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 =
            `
` + this.moments[j].id + " " + this.moments[j].content + `
`; //给最小的管道添加卡片 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:

扩展

如果希望图片框大小一样,则设置图片为背景图片,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 =
    `
` + this.moments[j].id + " " + this.moments[j].content + `
`;

修改后的效果:

Vue 瀑布流布局+触底加载下一页(原生)_第2张图片

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

你可能感兴趣的:(vue)