效果
代码
页面
调用Page
<block wx:for="{
{4}}" wx:key="{
{item}}">
<view style="text-align:center;padding:20px">
<swipe-box>
<view slot="left" style="">
左侧内容
</view>
<view class="center"
style="height:100px;width:200px;background:#f4f4f4">
中间内容
</view>
<view slot="right" style="">
右侧内容
</view>
</swipe-box>
</view>
</block>
SwipeBox wxml
<view class="swipe-box"
bindtouchstart="touchstartHandle"
bindtouchmove="touchmoveHandle">
<view class="content {
{direction}}"
style="--left--:{
{
-leftCellWidth}}px;--right--:{
{
rightCellWidth}}px">
<view class="left-handle">
<slot name="left"/>
</view>
<slot/>
<view class="right-handle">
<slot name="right"/>
</view>
</view>
</view>
SwipeBox wxss
.swipe-box {
overflow: hidden;
display: inline-block;
}
.swipe-box > .content {
position: relative;
display: inline-block;
transition: transform .3s;
}
.left-handle {
position: absolute;
right: 100%;
top: 0;
height: 100%;
width: 150px;
background: #f3f4fd;
}
.content {
display: inline-block;
}
.right-handle {
position: absolute;
left: 100%;
top: 0;
height: 100%;
width: 150px;
background: #ddd;
}
.swipe-box > .content.left {
transform: translateX(var(--left--))
}
.swipe-box > .content.right {
transform: translateX(var(--right--))
}
SwipeBox js
const DISTANCE = 50
Component({
options: {
addGlobalClass: true,
virtualHost: true,
multipleSlots: true
},
externalClasses: ['custom-class'],
data: {
direction: '',
leftCellWidth: 0,
rightCellWidth: 0,
},
lifetimes: {
ready() {
const vm = this
vm.uuid = wx.guid()
//获取左右插槽元素宽度
vm.createSelectorQuery().selectAll('.left-handle,.right-handle').boundingClientRect(rects => {
vm.setData({
leftCellWidth: rects[0].width,
rightCellWidth: rects[1].width
})
}).exec()
wx.RE.on('swipe-move', (uuid) => {
if (vm.uuid != uuid) {
vm.setData({
direction: '' })
}
})
vm.startX = 0
vm.startY = 0
vm.handleLock = true
}
},
methods: {
touchstartHandle(e) {
//每次开始先解锁
this.handleLock = false
this.startX = e.changedTouches[0].clientX
this.startY = e.changedTouches[0].clientY
},
touchmoveHandle(e) {
if (this.handleLock) {
return
}
const vm = this
let {
startX, startY } = vm;
let slidingRange = 45; //
let touchMoveX = e.changedTouches[0].clientX;
let touchMoveY = e.changedTouches[0].clientY;
//当任意方向移动距离大于阈值后判定滑动完成
if (Math.abs(touchMoveX - startX) >= DISTANCE || Math.abs(touchMoveY - startY) >= DISTANCE) {
vm.handleLock = true
let angle = vm.angle({
X: startX, Y: startY }, {
X: touchMoveX, Y: touchMoveY });
let direction = '', oldDirection = vm.data.direction
//为了方便计算取绝对值判断
if (Math.abs(angle) > slidingRange && touchMoveY < startY) {
// 向上滑动
direction = oldDirection === 'down' ? '' : 'up'
}
if (Math.abs(angle) > slidingRange && touchMoveY > startY) {
// 向下滑动
direction = oldDirection === 'up' ? '' : 'down'
}
if (Math.abs(angle) < 45 && touchMoveX < startX) {
// 向左滑动
direction = oldDirection === 'right' ? '' : 'left'
}
if (Math.abs(angle) < 45 && touchMoveX > startX) {
// 向右滑动
direction = oldDirection === 'left' ? '' : 'right'
}
vm.setData({
direction })
wx.RE.emit('swipe-move', vm.uuid)
}
},
//计算滑动角度 start 起点坐标 end 终点坐标
angle(start, end) {
//返回角度 Math.atan()返回数字的反正切值
return 360 * Math.atan((end.Y - start.Y) / (end.X - start.X)) / (2 * Math.PI);
}
}
})
备注
代码中出现的如下内容可自行实现
wx.RE
为全局事件管理,用于管理SwipeBox 之间以及与其他内容的交互
guid()
自定义唯一索引函数