better-scroll与UC浏览器滑动翻页冲突的js解决方案
问题:
最近在用vue写m端项目时发现个问题,better-scroll的横向滑动和UC浏览器的横向滑动翻页效果出现了冲突。
简单的说,就是滑动scroll组件的时候也会触发UC浏览器自带的翻页效果。
为此在网上找了不少资料,目前网上出现最多的解决方案是使用history.pushState(),使用监听事件,监听到跳页事件(popstate)时,手动填充路径为当前页面地址。
示例代码如下(引用):
history.pushState(null, null, document.URL);window.addEventListener('popstate', function () {
history.pushState(null, null, document.URL);
});
但是我个人在使用的时候发现了另外一个问题,这个代码不太符合我的需求场景,我只需要在scroll横向滑动禁止翻页,这个代码相当于将所有跳页操作禁止了。
于是我在这个基础上做了些一点改动,首先监听滑块的滑动,然后在滑块滑动的时候再去调用history.pushState,这样在scroll滑动的时候就阻止了UC浏览器的默认翻页。但是这样又引发另外一个问题,浏览器history的前进和后退是依靠的是浏览历史的队列,调用 history.pushState(null, null, document.URL) 就相当于往当前队列插入了一个当前页的历史记录。这样的话,每次使用浏览器自带的前进后退功能的时候都需要连续触发很多次才能跳出当前页,这样对于用户来说显然是不合理的。
那么,我们现在换一种思路来解决这个问题。
思路:
我们虽然不能禁止浏览器的跳转操作,但是我们可以阻止滑动元素触发的所有默认事件啊。然后只需要判断在什么时候去阻止默认事件以及恢复默认事件就好了。然后也不会影响点击等操作。
代码(基于vue):
- 往滑块的html结点上挂载触摸事件
<div @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"> </div>
- 往data上挂载数据
data() { return { isTouchMove: true, startX: 0, startY: 0, endX: 0, endY: 0, isPreventDefault:false }; }
- mounted上挂载触摸执行事件
methods: { touchStart(e){ // 获取初始位置 this.startX = e.touches[0].clientX; this.startY = e.touches[0].clientY; // 记录是否进入过touchMove this.isTouchMove = true; }, touchMove(e){ // 如果是UC浏览器 并且第一次滑动执行时 if (this.isTouchMove && this.isUC()) { this.endX = e.touches[0].clientX; this.endY = e.touches[0].clientY; // 判断滑动方向 横向 | 垂直 if (Math.abs(this.endX - this.startX) > Math.abs(this.endY - this.startY)) { // 如果滑动为横向,那么禁止所有默认事件 // 必要!否则会影响纵向页面的滚动 e.preventDefault() // 用来辅助判断是否已经禁止过默认事件 this.isPreventDefault = true; } // 关闭处理逻辑 touchMove连续触发就没必要再进来了 this.isTouchMove = false; } }, touchEnd(e){ // 如果已经禁止过默认事件 那么恢复默认事件 if(this.isPreventDefault && this.isUC() && e.preventDefault ){ // 恢复默认事件 e.preventDefault() this.isPreventDefault = false; } }, isUC(){ // 判断是否UC浏览器 return navigator.appVersion.indexOf('baidubrowser') !== -1 } }