微信小程序movable-area+movable-view,自动吸附两边
一、效果:拖动红框,中间位置释放,会判断吸附左边还是右边,会缓慢吸附两边,点击红块会触发事件,点击内容会触发点击内容,互不干扰。流畅度好,效果绝佳。

二、实现方法
1、wxml:
点击会触发点击事件
2、wxss:
page{width: 100%;min-height: 100%;
}
.cont{padding-top: 180rpx;width: 100%;
}
.movable-area{pointer-events:none;position: fixed;top: 0;left: 0;width: 100%;height: 100%;
}
.movable-view{pointer-events:auto;width: 120rpx;height: 120rpx;
}
.movable-view-main{width: 120rpx;height: 120rpx;background: #f00;
}
3、js
const app = getApp()
// 这里随便初始化一个变量,记录滑块滑动的时候的 X,Y,之所以这样弄,是因为 setData 性能原因,写这里会好一些,不需要一直 setData 了
let movableTmpX = 0,movableTmpY = 0,movableChangeFlag = false // 是否移动
Page({data: {x: 0,y: 0,viewportInfo: null, // 视口样式信息movableAreaInfo: null, // movableArea 样式信息movableViewInfo: null, // movableView 样式信息movableViewAnimation: false // movableView 动画是否开启},onReady: function () {// 之所以写在这里,是因为毕竟是初始化样式嘛,写在 onLoad 和 onShow 里边都不能确保样式已经渲染完毕,页面已经准备完毕了,所以写在 onReady 里边初始化const query = wx.createSelectorQuery().in(this) // 这个 in(this) 在自定义组件内部使用相当有用,这里有没有都行query.selectViewport().boundingClientRect()query.selectAll('#movableArea,#movableView').boundingClientRect()query.exec(res => { // 统一获取样式let viewportInfo = res[0] // 这里可以获取当前屏幕视口的宽高,如果设置 movableArea 区域的话,这个相当有用,这里没用上let movableAreaInfo = res[1][0] // 这是获取的 movableArea 样式let movableViewInfo = res[1][1] // 这里获取的 movableView 样式let x = movableAreaInfo.width - movableViewInfo.widthlet y = movableAreaInfo.height - movableViewInfo.height-60this.setData({x,y,viewportInfo,movableAreaInfo,movableViewInfo})setTimeout(() => {this.setData({movableViewAnimation: true // 初始化 x y 之后把动画打开,注意:一定要和上边的设置 x y 初始值区分开,不然设置初始值的时候还是会过渡过去,这个就没意义了})})})},// 滑动滑块 记录滑块当前的 X,YmovableViewChangeHandler: function ({detail}) {let {x,y,source} = detailif (source === 'touch') { // 这里是只记录手指滑动的 X YmovableChangeFlag = true // 代表移动过movableTmpX = x // 记录滑块当前的 XmovableTmpY = y // 记录滑块当前的 Y}},// 手指滑动结束事件movableViewTouchEndHandler(){if(movableChangeFlag){ // 移动过才触发,不移动单纯点击不触发let {width: movableAreaWidth,height: movableAreaHeight} = this.data.movableAreaInfolet {width: movableViewWidth,height: movableViewHeight} = this.data.movableViewInfolet tmpX = 0,tmpY = movableTmpY// 计算当前 X 偏向于左还是右if (movableTmpX + movableViewWidth / 2 > movableAreaWidth / 2) { // 如果偏向于右侧,则向右靠拢tmpX = movableAreaWidth - movableViewWidth // 设置 X 为最右侧} else { // 如果偏向于左侧,则向左靠拢tmpX = 0 // 设置 X 为最左侧}// 第一次设置 X,Ythis.setData({x: tmpX,y: tmpY})// 第二次设置 X,Y ,实际上这里只需要设置 Y 就行了,因为有问题的是 Y,不过这里把 X 也设置了,防止 X 也有问题setTimeout(() => {this.setData({x: tmpX,y: tmpY})// 其实这里延迟不给就行,但是为了确保可行性,还是协商了 20ms 的延迟,基本上没啥感知},20)movableChangeFlag = false // 重置为未移动过}},click_cont(){console.log("触发内容点击事件")},click_fk(){console.log("触发红块状点击事件")},
})
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
