前阵子接到一个需求,写一个新闻类的 app,内容高度不定,而且还要可以上下翻页滑动。想了一下,最简单的方案应该就是全屏 swiper,这样我可以少些很多动作事件。
但是写着写着发现有一个问题,swiper 一般都是图片滑动,对应广告之类的,一夜一页的翻转查看,而缺少内容滑动的机制。而当我设置了内容可以滑动时,当到顶或者到底之后,缺失了全屏翻页的事件,这就很难受。只能自己去判断了。
使用到的内容:
- vue-awesome-swiper@^4
- swiper@^5
要判断其实也不难,方案很多,但都不尽善尽美。最后发现通过单独控制 allowSlidePrev
和 allowSlideNext
的方案是最好的。
首先,在内部页面组件中绑定 touchstart
和 touchmove
事件,end 不太需要。
我们要实现的效果是每次滑动时,判断是否可以上/下滑屏即可,所以判断的工作放在 start 事件中就刚刚好,move 事件只负责动态更新状态,方便下次滑动时使用即可。
然后,我们需要在 touchmove
事件中更新内容滚动高度,并更新位置状态:
onTouchmove(e) {
if (this.isAtTop && this.isAtBottom) return;
const currentY = e.touches[0].clientY;
const diff = this.movedY - currentY;
if (this.isAtTop && diff < 0) return;
if (this.isAtBottom && diff > 0) return;
this.ref.scrollTop += diff;
// 判断是否到达顶部或底部
this.isAtTop = this.ref.scrollTop === 0;
this.isAtBottom =
this.ref.scrollHeight - this.ref.scrollTop - this.ref.clientHeight < 2;
this.movedY = currentY;
e.preventDefault();
}
接下来,在 touchstart
事件中,分别判断当前页面是否处于顶部/底部,这两个分别判断,并抛出对应值,方便 swiper 接收:
onTouchstart(e) {
this.movedY = e.touches[0].clientY;
this.isAtTop = this.ref.scrollTop === 0;
this.isAtBottom =
this.ref.scrollHeight - this.ref.scrollTop - this.ref.clientHeight < 2;
this.$emit("allowPrev", this.isAtTop);
this.$emit("allowNext", this.isAtBottom);
}
ref 是整屏内容
需要注意的是,我们获取,当我们获取到这个页面元素的高度后,不能直接使用纯等的方式判断(顶高+屏高 === 滚动高度),有时候浏览器会返回小数,这会导致永远不会到底,所以使用一个相对值即可。
最后,我们只需要在 swiper 中接收对应事件,并更新状态即可:
<comp
@allowPrev="v => {$refs.swiperRef.$swiper.allowSlidePrev = v}"
@allowNext="v => {$refs.swiperRef.$swiper.allowSlideNext = v}"
/>
swiperRef 绑定对应的 Swiper 组件
这样,就基本实现了一个简单的页面翻页滑动,并且内容可以自己滑动,当滑动到顶部/底部的时候,不会再滑动,而是等下一次滑动时,会触发 swiper 的翻页,这种体验效果是最好的。
文章评论