微信小程序——监听页面滑动(二)判断用户在做向上滑动还是向下滑动(onScrollPage scroll-view)

场景复现

在上期文章中,我们简单介绍了如何监听页面滑动,但是在文章的最后留下了一个问题。我们如何判断用户是在做上滑操作还是下滑操作?本期文章将用两种方法(onPageScroll或者touchstart、touchmove、touchend)解决这个问题。

核心干货 

onPageScroll结合scrollTop实现
在上期文章中,关于onPageScroll的用法已经介绍的很全面了。这里的话就直接写逻辑层的内容。
首先我们能监听页面变化的参数只有scrollTop,所以我们需要从scrollTop的变化下手。在上期文章中,我们发现当页面上滑时scrollTop递增,页面下滑时scrollTop递减。所以我们可以通过判断scrollTop的变化来判断用户的动作。

data:{
	scrollTopArr:<number[]>[]
}
onPageScroll: function(e) {
    var that = this
    var scrollTop = e.scrollTop;
    var scrollTopArr = that.data.scrollTopArr;
    scrollTopArr.push(scrollTop)
    var len = scrollTopArr.length;
    len > 5 ? scrollTopArr.slice(0,len-4):scrollTopArr;
    if(scrollTopArr[len-1] > scrollTopArr[len-2]){
      console.log("上滑")
    } else if(scrollTopArr[len-1] < scrollTopArr[len-2]) {
      console.log("下滑")
    }

现在理一下逻辑,由于onPageScroll是实时调用执行的,所以我们需要对每次获取到的数据进行存储,所以有了第一部分的data代码,首先定义一个数组用来存放每次调用的scrollTop。但是我们需要考虑到,这个函数调用是非常频繁的,所以一次的数据会有几百上千和数据,因此我们在做数据比较的时候,需要对代码进行截取,所以有了代码截取的部分。

上滑和下滑的监听都实现了。下面我们简单介绍一下第二种方法。

了解touch方法

微信小程序中可以通过监听touchstarttouchmovetouchend事件来判断用户的滑动方向。

具体方法如下:

  1. touchstart事件中记录下手指触摸的位置startY

  2. touchmove事件中记录下手指移动的位置moveY

  3. touchend事件中比较startYmoveY的大小,如果moveYstartY大,则用户是在向上滑动,反之则是向下滑动。

以下是示例代码:

let startY = 0;

// 监听touchstart事件
function handleTouchStart(e) {
  startY = e.touches[0].clientY;
}

// 监听touchmove事件
function handleTouchMove(e) {
  const moveY = e.touches[0].clientY;
  const direction = moveY > startY ? 'up' : 'down';
  console.log(`用户正在向${direction}滑动`);
}

// 监听touchend事件
function handleTouchEnd(e) {
  const moveY = e.changedTouches[0].clientY;
  const direction = moveY > startY ? 'up' : 'down';
  console.log(`用户向${direction}滑动结束`);
}

// 绑定事件
const element = document.querySelector('.scrollable-element');
element.addEventListener('touchstart', handleTouchStart);
element.addEventListener('touchmove', handleTouchMove);
element.addEventListener('touchend', handleTouchEnd);
<think> 根据用户的问题,用户希望实现微信小程序监听左右滑动手势并实现返回页面的功能。 参考提供的引用内容,我们可以知道如何监听左右滑动手势: 1. 在wxml中,为view绑定touchStart、touchMove和touchEnd事件(引用[1][2][3]都提到了)。 2. 在js中,定义这些事件的处理函数,通过计算触摸开始和结束时的坐标差来判断滑动方向。 但是,用户还希望实现返回页面的功能。在微信小程序中,返回页面可以使用`wx.navigateBack`方法。 结合引用[2]中的代码,我们可以: 在判断出左滑或右滑后,调用返回页面的方法。不过,通常返回页面是左滑(类似于iOS的返回手势)或者右滑(安卓常见),这里我们可以根据需求设定,例如右滑返回(从左边边缘向右滑动)。 注意:引用[2]中,当tmX<0时是左滑,大于0是右滑。但是我们通常的返回手势是右滑(从屏幕左侧边缘向右滑动),所以我们可以监听右滑,然后执行返回。 但是,为了避免误触,通常我们只处理从屏幕边缘开始的滑动(例如从左侧边缘开始向右滑动)。不过引用中并没有处理边缘情况,我们可以进行改进。 因此,我们可以: 1. 在touchStart事件中,记录触摸点的X坐标,并判断是否在屏幕边缘(比如距离左侧10像素以内)。 2. 在touchEnd事件中,判断滑动方向,如果是右滑(tmX>0)且开始位置在边缘,则执行返回。 但是,引用[2]的代码中,只记录了按下的点,没有记录是否在边缘。所以我们需要改进。 然而,用户的需求中并没有特别要求边缘触发,我们可以先实现基本的右滑返回,然后如果需要边缘触发,再添加条件。 步骤: 1. wxml文件中,在需要监听滑动页面最外层view上绑定事件(或者整个页面,可以根据需要选择元素)。 2. 在js文件中,定义触摸开始和结束的事件处理函数。 3. 在touchStart中,记录触摸开始的X坐标(以及Y坐标,用于排除上下滑动),同时可以设置一个标志位记录是否从边缘开始(可选)。 4. 在touchEnd中,计算滑动距离,判断方向,如果是右滑,则调用`wx.navigateBack`返回上一页。 但是,要注意,引用[2]中还使用了一个计时器来判断滑动时间,避免长按也被误认为是滑动。我们可以参考这个时间判断,比如时间小于300毫秒(即30,因为每100毫秒计数一次,所以time<3表示300毫秒内)?但引用[2]中用的是time<20(即2000毫秒)?这个时间似乎太长,通常手势在几百毫秒内完成。我们可以调整。 我们优化一下逻辑: - 记录触摸开始和结束的时间戳(而不是用setInterval),这样更精确。 - 计算滑动距离,水平距离大于一定值(如50)且垂直距离小于一定值(避免上下滑动干扰),且时间在300毫秒内。 考虑到性能,我们可以不使用setInterval,而是用Date对象记录时间。 具体实现: wxml: ```html <view bindtouchstart="touchStart" bindtouchend="touchEnd" style="height: 100%;"> <!-- 确保高度占满,整个页面都可以滑动 --> <!-- 页面内容 --> </view> ``` js: ```javascript Page({ data: {}, touchStartTime: 0, // 触摸开始时间 touchStartX: 0, // 触摸开始的X坐标 touchStartY: 0, // 触摸开始的Y坐标 // 触摸开始事件 touchStart: function(e) { this.touchStartTime = Date.now(); this.touchStartX = e.touches[0].pageX; this.touchStartY = e.touches[0].pageY; }, // 触摸结束事件 touchEnd: function(e) { const endTime = Date.now(); const touchEndX = e.changedTouches[0].pageX; const touchEndY = e.changedTouches[0].pageY; const timeDiff = endTime - this.touchStartTime; // 触摸时间差 const diffX = touchEndX - this.touchStartX; // X方向滑动距离 const diffY = touchEndY - this.touchStartY; // Y方向滑动距离 // 判断是否为右滑:X方向为正(从左向右滑),且水平距离大于50,垂直距离小于50(避免斜滑),且时间在300ms内 if (Math.abs(diffX) > 50 && Math.abs(diffY) < 50 && timeDiff < 300) { if (diffX > 0) { // 右滑,执行返回 wx.navigateBack({ delta: 1 // 返回上一页 }); } } } }); ``` 注意:这里我们只处理了右滑返回,左滑可以根据需要处理(比如前进,但小程序没有内置前进,可能需要自己维护页面栈)。 但是,用户可能希望整个页面都可以右滑返回,或者只在页面左侧边缘右滑返回(像iOS那样)。我们可以修改为只处理从边缘开始的滑动: 在touchStart中,我们可以判断起始X坐标是否小于某个阈值(例如30像素): ```javascript touchStart: function(e) { this.touchStartTime = Date.now(); this.touchStartX = e.touches[0].pageX; this.touchStartY = e.touches[0].pageY; // 记录是否从边缘开始,这里我们只关心右滑(从左侧边缘开始) this.isFromEdge = this.touchStartX < 30; // 假设30像素内为边缘 }, ``` 然后在touchEnd中,增加条件: ```javascript if (Math.abs(diffX) > 50 && Math.abs(diffY) < 50 && timeDiff < 300 && this.isFromEdge) { if (diffX > 0) { wx.navigateBack({ delta: 1 }); } } ``` 这样,只有从左侧边缘开始向右滑动才会触发返回。 但是,注意:如果页面中有滚动条,左右滑动可能会和滚动冲突,所以我们需要考虑是否要阻止滚动。不过,微信小程序的touch事件不会阻止滚动,所以如果我们在垂直滚动时,可能会同时触发滑动事件。因此,我们在判断时加入垂直方向的限制(|diffY|<50)可以避免大部分误触。 另外,如果页面内容有横向滚动,那么右滑返回可能会和横向滚动冲突。因此,通常右滑返回只在页面最左侧边缘触发,并且可以设置一个开关来控制是否启用。 最后,如果用户希望左滑也能触发某个操作(比如返回上一页在历史记录中可能是前进,但小程序没有前进),这里我们只处理右滑返回。 总结:我们可以通过触摸事件监听用户手势,判断为右滑后调用`wx.navigateBack`实现返回。 因此,回答如下: </think> 在微信小程序中实现监听左右滑动手势并返回页面的功能,可以通过以下步骤实现: ### 实现步骤 1. **绑定触摸事件** 在 WXML 文件的根`<view>`中绑定触摸事件: ```html <view bindtouchstart="touchStart" bindtouchend="touchEnd" style="height: 100%;" <!-- 确保覆盖整个页面 --> > <!-- 页面内容 --> </view> ``` 2. **JS 逻辑实现** 在对应的 JS 文件中实现手势判断和返回逻辑: ```javascript Page({ data: { touchStartX: 0, // 触摸起始X坐标 touchStartTime: 0 // 触摸开始时间 }, // 触摸开始事件 touchStart(e) { this.setData({ touchStartX: e.touches[0].pageX, touchStartTime: Date.now() // 记录开始时间戳 }); }, // 触摸结束事件 touchEnd(e) { const endX = e.changedTouches[0].pageX; const endTime = Date.now(); const { touchStartX, touchStartTime } = this.data; // 计算滑动距离和时间差 const diffX = endX - touchStartX; const diffTime = endTime - touchStartTime; // 判断为右滑(距离>50px, 时间<300ms) if (diffX > 50 && diffTime < 300) { wx.navigateBack({ delta: 1 }); // 返回上一页 } } }); ``` ### 关键逻辑说明 1. **手势判定条件**: - `diffX > 50`:水平滑动距离需大于 50 像素(避免误触) - `diffTime < 300`:滑动过程需在 300 毫秒内(确保是快速滑动) 2. **返回页面**: 通过 `wx.navigateBack({ delta: 1 })` 返回上一级页面[^2]。 (`delta: 1` 表示返回层数,可调整) 3. **边缘触发优化(可选)**: 若需模仿 iOS 边缘返回效果,可在 `touchStart` 中增加位置判断: ```javascript touchStart(e) { if (e.touches[0].pageX > 30) return; // 仅左侧30px内触发 // ...记录坐标 } ``` ### 注意事项 - **页面层级**:确保绑定事件的 `<view>` 是页面根节点且高度为 100% - **冲突处理**:若页面有横向滚动区域,需在子组件中调用 `catchtouchmove` 阻止事件冒泡 - **性能**:避免在事件中执行复杂操作,仅记录必要数据 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嫣嫣细语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值