问题
之前做过一个关于闯关的项目,一个分类里面都有600个小关卡,用户需要滚动选择关卡,为了能让页面看起来很好看,所以就做了个无限滚动的页面。
无限滚动
思路
- 无限滚动并不是真的一直在滚动,而是两张或者更多的可以
无限链接
的图片相互的变换所在的位置。ps:(就像人民币,两张人民币怎么拼接花纹都能对应)
- 无限滚动并不是真的一直在滚动,而是两张或者更多的可以
- 2.人之所以认为你把图片滑动了,并不是它真的动了,它可以是相对于你的手机屏幕移动而已
-
3.只要在手指滑动的时候记录手指滑动的高度轨迹,然后让图片的定位相对应的滚动即可
分析图
由上图可分析:
两张图片的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
从上图分析组合这个公式结果是
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 无限滚动 - 初级无限滚动
网友评论