微信小程序中悬浮窗功能的实现代码(2)

你又以为你的测试一定能发现这个问题?发现了又怎样,我已经尽力了,还给你整出这么多理论依据,足够你把锅牢牢地按在微信小程序官方的头上。

使用movable-view:仿佛发现了新大陆,结果发现这个还是个弟弟

甩锅是一定要甩锅的,但是段位要高。

所以要遍查官方文档,探讨一切可能性,以免甩锅的时候被打脸。

我们仔细观察小程序官方文档,发现还是有个专门用来拖动的组件叫movable-view。

这个组件和cover-view摆放在一起仿佛很厉害的样子,紧接着我们在原生组件使用限制文档中发现了它并不是原生组件。

也就是说这个东西的层级一定还是低于咱们的textarea组件的。

虽然已经很确定这个东西没什么用了,但是最后还是试探一把,结果发现是个真弟弟,这里就不给出代码了。

我写这个弟弟方案放在这里的目的主要是为了不要浪费你的验证时间。

理论上行得通的方案:将拖动事件的捕获放在父级

现在我们确认的最优甩锅方案里,已经实现了功能和甩锅两不误。

那么作为一名有追求的技术人员,还是需要去探讨以下这个问题到底有没有完美的解决方案。

因为我最开始是把这个悬浮窗做成了一个组件,那么作为组件来讲,这个东西就只能做到这个地步了。

不过如果你是像我现在的例子一样直接做在了页面里,那么实现起来也不是说没有办法的。

我们将拖动的事件放在父级上就可以了,请看接下来的代码:

index.wxml: <view bindtouchmove="setTouchMove"> <view bindtap="goToHome"> <image src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </image> </view> <textarea placeholder='我是textarea组件,用来输入一些信息'></textarea> <view> 一大段test,占个位,表示下存在感 </view> </view> index.js: Page({ /** * 页面的初始数据 */ data: { left: 20, top: 250 }, /** * 拖拽移动 */ setTouchMove: function (e) { const MOVE_VIEW_RADIUS = 30 // 悬浮窗半径 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY const moveViewCenterPosX = this.data.left + MOVE_VIEW_RADIUS const moveViewCenterPosY = this.data.top + MOVE_VIEW_RADIUS // 确保手指在悬浮窗上才可以移动 if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS + 60 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS + 60) { if (touchPosX > 0 && touchPosY > 0) { this.setData({ left: touchPosX - MOVE_VIEW_RADIUS, top: touchPosY - MOVE_VIEW_RADIUS }) } else { this.setData({ left: 20, // 默认显示位置 left距离 top: 250 // 默认显示位置 top距离 }) } } }, /** * 返回首页 */ goToHome: () => { wx.reLaunch({ url: '/pages/index/index', }) } })

关键代码就是这块了:

// 确保手指在悬浮窗上才可以移动 if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS + 60 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS + 60) { }

只要确保手指在悬浮窗的范围内就可以触发移动了,这里的60是为了确保你的手指太大,或者移动得比较快时超出了悬浮窗区域依然可以触发拖动,这个可以自己设定数值。

这个方案在理论上很合理,并且还加上了60这个缓冲区域,但是实际在拖动的时候你仍然会面临下面三个问题:

1.如果悬浮窗下方有滚动区域,那么拖动的时候就会滚动页面,效果会显得比较奇怪。
2.实际移动没法移动太顺畅,只能拖着悬浮窗亦步亦趋,要不然很容易超过60这个缓冲区域,导致拖动不继续触发。
2.如果将缓冲区域设置过大,那么又会出现一种比较奇怪的场景:明明不准备拖动悬浮窗,只是准备滑动页面,悬浮窗却跳到自己手指这里了。

进阶解决方案:禁止冒泡的拖动 + 理论方案

这个解决方案基于我们的最初方案,并且使用我们的理论方案作为补充。

先上代码:

index.wxml: <view bindtouchmove="handleSetMoveViewPos"> <view bindtap="goToHome" catchtouchmove="handleTouchMove"> <image src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </image> </view> <textarea placeholder='我是textarea组件,用来输入一些信息'></textarea> <view> 一大段test,占个位,表示下存在感 </view> </view> index.js: Page({ /** * 页面的初始数据 */ data: { left: 20, top: 250 }, /** * 拖拽移动(补丁) */ handleSetMoveViewPos: function (e) { const MOVE_VIEW_RADIUS = 30 // 悬浮窗半径 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY const moveViewCenterPosX = this.data.left + MOVE_VIEW_RADIUS const moveViewCenterPosY = this.data.top + MOVE_VIEW_RADIUS // 确保手指在悬浮窗上才可以移动 if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS+30 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS+30 ) { if (touchPosX > 0 && touchPosY > 0) { this.setData({ left: touchPosX - MOVE_VIEW_RADIUS, top: touchPosY - MOVE_VIEW_RADIUS }) } else { this.setData({ left: 20, // 默认显示位置 left距离 top: 250 // 默认显示位置 top距离 }) } } }, /** * 拖拽移动 */ handleTouchMove: function (e) { const MOVE_VIEW_RADIUS = 30 // 悬浮窗半径 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY if (touchPosX > 0 && touchPosY > 0) { this.setData({ left: touchPosX - MOVE_VIEW_RADIUS, top: touchPosY - MOVE_VIEW_RADIUS }) } else { this.setData({ left: 20, //默认显示位置 left距离 top: 250 //默认显示位置 top距离 }) } }, /** * 返回首页 */ goToHome: () => { wx.reLaunch({ url: '/pages/index/index', }) } })

这个方案的核心点在于:catchtouchmove="handleTouchMove" 。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/796e68fd5c943f6976cba2147857ca6b.html