微信小程序中浮动窗口功能的实现代码
问题场景
所谓浮动窗口,就是图片中微信图标的按钮,是固定的,可以拖拽点击。
这是一个相对常见的实现场景。
为什么要用覆盖视图作为浮动窗口?原生成分出来扛锅~
起初,我没有使用封面视图,而是视图。
这是一个简化的代码结构:
index . wxml : view class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' settouch move ' image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/image/view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textareview是一大段测试,占用一位。表示存在/viewindex.js:Page({ /** *页面的初始数据*/data: {left: 20,top: 250,isios: true},/** *拖动并移动*/settouchmove : function(e){ if(e . touch[0])。client x0e . touchs[0]。client 0){ this . setdata({ left : e . touches[0])。clientx-30,top:e。触摸[0]。client y-30 })else { this。setdata ({left: 20,//默认显示位置left : 250//默认显示位置top3360 250)},/* * *返回主页*/gotohome 3360()={ wx . reload({ URL : '/pages/index/index ',})})为什么要使用cover-view?
因为页面上有一个textarea组件,它是一个本机组件,所以当浮动窗口移动到此textarea组件时,它将无法继续拖动和单击。
如果浮动窗口一开始就定位在textarea上,那就更糟了,一开始就不能点击拖动。
这是因为微信小程序的原生组件级别比非原生组件高,不是你修改几次样式就能解决的问题。
我在这里不讨论本机组件。如果想了解更多,可以参考我之前写的一篇博客:e-echart图表在ios下无法滑动的解决方案。
如果您的页面上没有本机组件,只需像上面的代码一样将视图用作浮动窗口。
如果是这样,你可以跟着我继续踩坑,用cover-view,一个原生组件级别的组件,作为一个浮动窗口。
安卓拖动下的封面视图,像帕金森一样颤抖,像魔鬼的步伐
以下是我们将其修改为cover-view后的代码:
cover-view class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' settouch move ' cover-image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/cover-image/cover-view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textareview是一大段测试,占用一点,表示存在感/视图。请注意,我们的图像也已更改为封面图像。因为封面视图只支持嵌套的封面视图和封面图像,所以可以在封面视图中使用按钮。
虽然这样解决了你可以在原生组件上自由拖拽和点击的问题,但是在Android上有一个非常奇怪的现象,所以我觉得不能再用抖动来形容了:
上图是我滑动浮动窗口后的效果。我只是慢慢地移动手指,但漂浮的窗户表现得像一只受惊的兔子。
当我第一次看到这种效果时,我看起来很困惑,不知道该说什么。
虽然cover-view在ios上移动很好,但在安卓上拖动时就看不到了。
几乎看不到的补丁方案
安卓太差了,不如原来的好。
所以来个补丁计划,在ios下用cover-view完美拖动,在Android上用view先运行。
cover-view wx-if=' { { ISIOs } } ' class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' settouch move ' cover-image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/cover-image/cover-view view wx-if=' { {!isIos } } ' class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' settouch move ' image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/image/view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textareview是一大段测试,占用一点,表示存在感。/view,当然,这段代码必须添加到js:
Onload:函数(选项){wx。getsystem info({ success :(RES)={ if(RES . platform=' Android ')){ this。setdata ({isIos: false})}})}不要忘记isIos默认为true。
无论如何,它可以完美地在ios环境中使用。至于安卓下不能拖到textarea组件的问题,只需要调整悬浮盒的初始位置即可。
而且,只要不是故意移动到textarea组件,拖动悬浮框经过textarea组件也没问题。
像我这样的聪明用户知道如何滑动下面的页面,将浮动窗口移动到本机组件之外的地方,这样就可以再次拖动它。
你认为你的测试会发现这个问题吗?不管怎样,我已经尽力了,我给了你这么多理论依据,你可以牢牢按在微信小程序官方头上的锅。
使用可移动视图:好像发现了新大陆,原来这还是弟弟
甩锅是必须的,但舞台要更高。
所以要翻看官方文件,探索一切可能,以免扔锅的时候被打脸。
我们仔细观察小程序的官方文档,发现还是有一个专门用于拖拽的组件叫做移动视图。
这个组件和cover-view放在一起就好像它们非常强大,然后我们发现它不是本机组件使用限制文档中的本机组件。
也就是说,这个东西的等级肯定还是比我们的textarea组件低。
虽然很确定这个东西没用,但我最后还是试了一下,发现是真兄弟,所以这里就不给出代码了。
把这个兄弟计划放在这里主要是为了不浪费你的验证时间。
理论上可行的方案:将拖动事件的捕获放在父级
现在,在我们确定的最佳抛锅方案中,我们实现了功能和抛锅。
那么,作为一个有抱负的技术人员,就有必要探讨一下,对于下面的问题是否有一个完美的解决方案。
因为我一开始把这个浮动窗口做成一个组件,作为一个组件,这个东西只能做这个。
然而,如果你像我现在的例子一样直接在页面上做,并不是没有办法实现。
我们可以把被拖动的事件放在父级上,请看下面的代码:
index . wxml : view bindochmove=' setTouchMove ' view class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/image/view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textarea view是一大段测试,占用一位。表示存在/视图/viewindex.js:page ({/* * *页面的初始数据*/data3360 {left: 20,top: 250},/* * *拖动并移动*/settouchmove : function(e){ const move _ view _ radius=30//浮动窗口半径const TouchPosx=e . touch[0]。client x const TouchPosy=e . Touchs[0]。clientY const moveviewcentposx=this . data . left MOVE _ VIEW _ RADIUS const moveviewcentposy=this . data . top MOVE _ VIEW _ RADIUS//在移动if(数学)之前,请确保手指在浮动窗口上。ABS(moveviewcentposx-touch posx)move _ view _ radius 60 path。ABS(moveviewcentposy-touch posy)MOVE _ VIEW _ RADIUS 60){ if(touch posx 0 touch posy 0){ This . setdata({ left : touch posx-MOVE _ VIEW _ RADIUS,top : touch pose-MOVE _ VIEW _ RADIUS })else { This . setdata({ left : 20,//默认显示位置left : 250//默认显示位置top3360 250)}},/* * *返回主页
//确保你的手指可以移动如果(数学。ABS(moveviewcentposx-touch posx)move _ view _ radius 60 path。ABS(moveviewcentposy-touch posy)move _ view _ radius 60){ }只要保证手指在浮动窗口的范围内,就可以触发移动。在这里,60是为了确保你的手指太大,或者你在移动超过浮动窗口区域时仍然可以触发拖动。你可以设定自己的价值。
这个方案理论上是合理的,增加了60的缓冲区,但是在实际操作中,拖动时还是会面临以下三个问题:
1.如果浮动窗口下方有滚动区,拖动时页面会滚动,效果会很奇怪。2.实际移动不能太流畅,只能拖动浮动窗口跟风,否则很容易超过60的缓冲区,导致拖动不继续触发。2.如果你把缓冲区设置的太大,就会出现一个奇怪的场景:很明显,你不是要拖动浮动窗口,而是要滑动页面,但是浮动窗口跳到你的手指上。
高级解决方案:一个阻止冒泡的阻力理论方案
这个解决方案是基于我们的原始解决方案,并辅以我们的理论解决方案。
代码优先:
index . wxml:view bindochmove=' handleSetMoveViewPos ' view class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' handletouch move ' image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/image/view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textarea view是一大段测试,占用一位。表示存在/视图/视图索引. js: page ({/* * *页面的初始数据*/data3360 {left: 20,top: 250},/* * *拖放(patch)*/handlesetmoveviewpos :函数(e){ const move _ view _ radius=30//浮动窗口半径const touchPosX=e.touches。client x const TouchPosy=e . Touchs[0]。clientY const moveviewcentposx=this . data . left MOVE _ VIEW _ RADIUS const moveviewcentposy=this . data . top MOVE _ VIEW _ RADIUS//在移动if(数学)之前,请确保手指在浮动窗口上。ABS(moveviewcentposx-touch posx)move _ view _ radius 30 path。ABS(moveviewcentposy-touch posy)MOVE _ VIEW _ RADIUS 30){ if(touch posx 0 touch posy 0){ this . setdata({ left : touch posx-MOVE _ VIEW _ RADIUS,top : touch pose-MOVE _ VIEW _ RADIUS })else { this . setdata({ left : 20,//默认显示位置left : 250//默认显示位置top3360 250)}},/* * *拖动并移动*/即可client x const TouchPosy=e . Touchs[0]。clientY if(touch posx 0 touch posy 0){ this . setdata({ left : touch posx-MOVE _ VIEW _ RADIUS,top : touch pose-MOVE _ VIEW _ RADIUS })else { this . setdata({ left : 20,//默认显示位置left : 250//默认显示位置top3360 250)},/* * * Back to Home */goto Home :()={ wx . relax({ URL 33660。
当我们正常拖动浮动窗口时,我们可以通过catchtouchmove捕捉浮动窗口上的滑动事件,而不会冒泡到父元素,因此绑定到父级别的滑动事件不会触发。
而当我们将浮动窗口拖动到原生组件上方时,由于我们不能点击浮动窗口,所以不会触发handleTouchMove函数,而只会触发绑定到父元素的handleSetMoveViewPos函数。
另外,如果你细心的话,你会发现我在handleSetMoveViewPos函数中把缓冲区缩小到了60到30。这样做的目的是触发这个功能只会在原生组件上,所以在多次称重距离后,尽量避免通过关闭滑动操作来触发和拖动悬浮盒。
通过我们的方案,我们可以在非原生组件上自由拖动,在原生组件上平滑拖动。
最初,我打算将这个方案作为最终方案,但是在ios下,当浮动窗口在本机组件上时,父元素上的滑动事件不会触发。
棋是一招,棋是一招!
最终的解决方案:更多补丁,更多快乐
当然,这个最终的解决方案是结合我们以前所有的补丁方案。
代码如下:
index . wxml : view bindochmove=' handleSetMoveViewPos ' view wx-if=' { {!isIos } } ' class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' handletouch move ' image class=' img ' src=' http :3359 ss 2 . Baidu.com/6 onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/image/view cover-view wx-if=' { { ISIOs } } ' class=' move-view ' style=' top : { { top } } px;' left: { { left } } px'bind tap=' GoToHome ' catch touch move=' handletouch move ' cover-image class=' img ' src=' http :3359 ss 2 . Baidu.com/6onysjip 0 qiz 8 tyhNq/it/u=4294841024,3545417298fm=179app=42f=PNG?w=56h=56 '/cover-image/cover-view textarea placeholder='我是一个textarea组件,用来输入一些信息'/textarea view是一大段测试,占用一位。表示存在/查看/viewindex.js:page ({/* * *页面的初始数据*/data3360 {left: 20,top: 250,isios: true},/* * *生命周期函数-监控页面加载*/onload:函数(选项){ wx . getsystem info({ success 3360(RES)={ if(RES . platform==' Android ')} { this。setdata ({isios: false})}})},/* * *拖放(patch)*/handlesetmoveviewpos :函数(e){//IOs下绝不会采用此方案,以免造成无用的计算if(!IOs){ const move _ view _ radius=30//浮动窗口radius const touch posx=e . touch[0]。client x const touch posy=e . touch[0]。clientY const moveviewcentposx=this . data . left MOVE _ VIEW _ RADIUS const moveviewcentposy=this . data . top MOVE _ VIEW _ RADIUS//在移动if(数学)之前,请确保手指在浮动窗口上。ABS(moveviewcentposx-touch posx)move _ view _ radius数学。ABS(moveviewcentposy-touch posy)MOVE _ VIEW _ RADIUS){ if(touch posx 0 touch posy 0){ this . setdata({ left : touch posx-MOVE _ VIEW _ RADIUS,Top: touch pose-MOVE _ VIEW _ RADIUS })else { this . setdata({ left : 20,//默认显示位置left : 250//默认显示位置top3360 250)}}},/* * *拖动并移动*/handletouchclient x const TouchPosy=e . Touchs[0]。clientY if(touch posx 0 touch posy 0){ This . setdata({ left : touch posx-MOVE _ VIEW _ RADIUS,top : touch pose-MOVE _ VIEW _ RADIUS })else { This . setdata({ left : 20,//默认显示位置left : 250//默认显示位置top3360 250)},/* * *返回主页*/gotohome 3360()={ wx . release({ URL 33330。
摘要
虽然问题已经解决了,但仍然只是一个补丁。
最好的办法就是官方微信小程序可以修复安卓手机中的cover-view的BUG,但是我发现有人在2018年11月第一次举报这个问题,现在2019年8月还没有结果。
如果微信小程序官方态度没有问题,只能说明这个问题的解决真的很难或者优先级不高。不管是哪一个,暂时都需要一个补丁方案。
这个方案并不完美,在一些边界的连接上可能还存在一些小问题,但至少是可用的,应该是大多数用户可以接受的。
以上是边肖介绍的微信小程序中浮动窗口功能的实现,希望对大家有所帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!如果你觉得这篇文章对你有帮助,请转载,请注明出处,谢谢!
版权声明:微信小程序中浮动窗口功能的实现代码是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。