最近遇到一个需求,有个悬浮按钮在某些情况下会遮挡内容,所以想把它做成可以全屏移动的。在小程序中实现一个可全屏拖动的悬浮按钮,我第一时间想到了微信官方组件 movable-area 和movable-view。

看起来好像没毛病,实际上悬浮的 movable-area 遮挡了底层的所有内容,底层无法点击、划动,也无法触发 onPullDownRefresh (下拉)事件。改进,将所有内容放进 movable-area 中。

内容是可以点击、拖动了、但是仍然无法触发下拉事件,而且 movable-area 必须固定宽高,内容拖动后看起来按钮不可全屏移动了。网上有方案说在这里使用 scroll-view来实现,并通过滚动的位置来触发对应的事件。

顺便贴上代码
<movable-area style="min-height:100vh;width:100vw;">
<scroll-view style="max-height:100vh;" scroll-y="true">
<!-- 内容部分 -->
</scroll-view>
<movable-view style="height: 100px; width: 100px; background: blue;" direction="all">
</movable-view>
</movable-area>
此方案确实可行,但是个人认为这个方案过于麻烦(主要在于要自行处理各种事件),因此、下决心自己写一个悬浮按钮的组件。
<!-- wxml -->
<view style="left:{{x}}px;top:{{y}}px;position: fixed;z-index: 1;" bindtap='show' bindtouchmove="touchmove">
<button>按钮</button>
</view>
// js
Component({
methods: {
touchmove({ changedTouches}){
let x = changedTouches[0].pageX
let y = changedTouches[0].pageY
this.setData({
x:x,
y:y
})
}
}
});
在要使用的页面引入此组件,效果如下:

但是内容层会跟随移动,所以在组件中捕获点击和移动事件。把tap改为catch。
<view style="left:{{x}}px;top:{{y}}px;position: fixed;z-index: 1;" catchtap='show' catchtouchmove="touchmove">
<button>按钮</button>
</view>
这已经很接近我们想要的效果了,

但我认为这并不完美,在touchmove事件是一个频繁事件,如果频繁的setData来设置坐标会带来性能的问题,重来!使用wxs在视图层实现。
//wxs代码
module.exports = {
touchmove: function(event, ownerInstance) {
var clientX = event.changedTouches[0].clientX
var clientY = event.changedTouches[0].clientY
var style = {}
var windowWidth = event.currentTarget.dataset.windowwidth
var windowHeight = event.currentTarget.dataset.windowheight
var instance = ownerInstance.selectComponent('.move')
if (clientX <= windowWidth) {
style.left = clientX + 'px'
style.right = 'auto'
} else {
style.right = '0px'
style.left = 'auto'
}
if (clientY <= windowHeight) {
style.top = clientY + 'px'
style.bottom = 'auto'
} else {
style.bottom = '0px'
style.top = 'auto'
}
instance.setStyle(style)
}
}
<!--wxml代码-->
<view class="move" style="left:{{x}}px;top:{{y}}px;position: fixed;z-index: 1;" catchtap='show' catchtouchmove="{{move.touchmove}}" data-windowwidth="{{data-windowwidth}}" data-windowheight="{{windowheight}}">
<button>按钮</button>
</view>
<wxs module="move" src="index.wxs"></wxs>
在这一版本中考虑了按钮拖出屏幕自动贴边(需要根据按钮的实际尺寸调整),至此,整个组件完成。如果大家有更好的方案欢迎与我讨论。



