vue - 初级无限滚动

2022-04-15  本文已影响0人  Petricor

问题

之前做过一个关于闯关的项目,一个分类里面都有600个小关卡,用户需要滚动选择关卡,为了能让页面看起来很好看,所以就做了个无限滚动的页面。


无限滚动

思路

由上图可分析:

两张图片的top值的范围是(bgh , - bgh]

<template>
    <div class="elementary-view" name="infinte" id="infinte">
      <div   v-for="(page, idx) in pages"   :key="idx"   class="group" 
        :style="{  top: page + 'px' }" >
        <img class="img" :src="stepBg1" />
      </div>
    </div>
</template>

<script>
import stepBg1 from "../../../assets/step-bg1.png";
export default {
  data() {
    return {
      pageW: 0, // 滚动区域宽度
      pageH: 0, // 滚动区域高度

      bgImgsW: 0, // 滚动图片的原始宽度 (可以根据图片直接写成定值)
      bgH: null, //比例高度
      pages: [0, 0], //定义两个图片的初始位置
      startY: 0,
      scrollTotal: 0, //滚动的总距离

      thinkShow: false,
      stepBg1: stepBg1,
    };
  },
  mounted() {
    // 获取屏幕宽度和高度
    let infinte = document.getElementById("infinte");
    this.pageW = infinte.clientWidth;
    this.pageH = infinte.clientHeight;

    // 获取滚动图片的高度
    let bgImg = document.createElement("img");
    bgImg.setAttribute("crossOrigin", "anonymous");
    bgImg.src = stepBg1;
    bgImg.onload = () => {
      this.bgImgsW = bgImg.width;
      this.bgH = this.getRatioVal(bgImg.height); //获取图片相对比例的高度

      this.pages[1] = -1 * this.bgH;
      this.$set(this.pages, 1, -1 * this.bgH);
    };

    //定义开始的手势
    infinte.addEventListener("touchstart", this.touchstart, {
      passive: false,
    });
   //定义结束的手势
    infinte.addEventListener("touchend", this.touchend, {
      passive: false,
    });
    //定义滚动的手势
    infinte.addEventListener("touchmove", this.touchmoveEvt, {
      passive: false,
    });
  },
  methods: {
    getRatioVal(val) {
      // 保留一位小数点
      const ratio = this.pageW / this.bgImgsW;
      return Math.ceil(val * 10 * ratio) / 10;
    },
    touchstart(evt) {
      this.startY = evt.changedTouches[0].screenY;
      evt.preventDefault();
    },
    touchend(evt) {
      let endY = evt.changedTouches[0].screenY;
      this.scrollTotal = this.scrollTotal + endY - this.startY; //总共滚动的高度
      this.startY = null;
      evt.preventDefault();
    },
    touchmoveEvt(evt) {
      let touchY = evt.changedTouches[0].screenY; //手指现在的位置
      let onceY = touchY - this.startY;
      this.updatePagePositon(onceY);
    },
    updatePagePositon(onceY) {
      let p = this.scrollTotal + onceY;
      let h = this.bgH;
      let offset = p % h; //余下了多少高度(相对滚动距离)
      let v = Math.floor(Math.abs(p) / h) % 2; //先判断滚动的数量是几个bgh,在相对位置不变的情况我们眼前应该是那个组件
      this.pages.forEach((val, i) => {
        let m = p < 0 ? -1 : 1;
        this.$set(this.pages, i, offset + (i - v) * h * (-2 * i + 1));
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.elementary-view {
    width: 100%;
    height: 100%;
    position: relative;
    background-color: #1990fe;
    overflow: hidden;
    &.layout-h {
      box-shadow: 2px -2px 4px 0px rgba(51, 51, 51, 0.2);
    }
    .group {
      position: absolute;
      left: 0;
      width: 100%;
      .img {
        width: 100%;
      }
    }
}
</style>

方案清晰思路明白,所以一起都变的简单明了,就唯独剩下计算了
**解析updatePagePositon 方法 **

    updatePagePositon(onceY) {
      let p = this.scrollTotal + onceY;   //获取总共的滚动的距离
      let h = this.bgH;                          // 定义图片高度
      let offset = p % h;                       //余下了多少高度(相对滚动距离)
      let v = Math.floor(Math.abs(p) / h) % 2;      //先判断滚动的数量是几个bgh,在相对位置不变的情况我们眼前应该是那个组件

从上面代码能看出 :
offset 是 真正滚动需要增加的距离,
v 值是 0 || 1

分析图 1

从上图分析组合这个公式结果是

offset + (i - v) * h * (-2 * i + 1)
//但是该结果在offset为正数时候没问题,为负数时有问题
分析图2

因为从分析图1 的出的结果能看出
offset + ( - h) === offset + (i - v) * h * (-2 * i + 1)
所以分析图2 能得出
offset + h === offset + (i - v) * h * (-2 * i + 1) * (-1)

      this.pages.forEach((val, i) => {
        let m = p < 0 ? -1 : 1;
        this.$set(this.pages, i, offset + (i - v) * h * (-2 * i + 1) * m);
      });

    },

代码地址:码云 vue-question 无限滚动 - 初级无限滚动

下一篇中级无限滚动

结束 送你们一张循环图

循环图
上一篇下一篇

猜你喜欢

热点阅读