用过微信的人几乎都知道,在微信中浏览网页时可以下拉查看网站的网址。这确实是一项实用的功能,使用户能够追溯内容提供者,减少被仿冒、钓鱼网站欺骗的风险。不过有时候它确实也对网页的操作产生了干扰。

举个例子,我想要给页面增加一个下拉刷新的功能,但是用户的手指在屏幕上滑动的时候会同时触发整个页面的下拉(显示网址)。这显然不是我想要的效果,必须想办法禁用或者阻止下拉显示网址这一默认动作。

有人建议这么做:

document.body.addEventListener('touchmove', (event) => {
  event.preventDefault()
})

确实,这样做能够取消 touchmove 事件(手指滑动)的全部默认动作,但页面的滚动也被一并禁用掉了。如果你的页面不需要滚动,当然可以这么做。我的想法是,只需要在页面滚动到最顶部,且用户的触摸操作为下拉时取消默认动作即可。

// 滑动起始点坐标
let coordStart = null

// 滑动结束点坐标
let coordEnd   = null

// 滚动的像素数
let scrollTop  = null

function preventWxPullDown () {
  // 监听 body 的 touchstart 事件
  document.body.addEventListener('touchstart', (event) => {
    // 触摸屏幕时保存一次起始点坐标和滚动像素数
    coordStart = [event.changedTouches[0].pageX, event.changedTouches[0].pageY]
    scrollTop = window.pageYOffset
  })
  // 监听 body 的 touchmove 事件
  document.body.addEventListener('touchmove', (event) => {
    // 保存结束点坐标
    coordEnd = [event.changedTouches[0].pageX, event.changedTouches[0].pageY]
    // 计算X轴和Y轴移动的距离
    const distance = [coordEnd[0] - coordStart[0], coordEnd[1] - coordStart[1]]
    // 符合条件时取消默认动作
    if (scrollTop == 0 && Math.abs(distance[0]) < Math.abs(distance[1]) && distance[1] > 0) {
      event.preventDefault()
    }
    // 更新起始点坐标和滚动像素数
    coordStart = [event.changedTouches[0].pageX, event.changedTouches[0].pageY]
    scrollTop = window.pageYOffset
  })
}

preventWxPullDown ()

preventWxPullDown 方法尝试在页面滚动到最顶部(即 scrollTop 等于0),且手指向屏幕下方滑动(即 Y 轴移动距离为正数且 Y 轴移动距离大于 X 轴移动距离)时取消默认动作。实测在阻止下拉显示网址的同时确实不会影响到页面的正常滚动,刚好满足我的需要。

Tips: 当手势为先上滑再下拉时无效。

相关环境:Windows 7 x64 / WeChat 6.5.16