程序员玛丽的星海方舟

关于我如何艰难地在公司业务中实现侧滑置顶删除功能(一)

工程需求

开发的应用:用微信小程序经由hera生成的跨平台移动端APP。

在“收藏列表”的模块中,需要添加一个类似于微信/QQ对话列表,对每一条信息左滑可以置顶或删除的功能。

方案参考

由于公司的APP构建框架似乎无法显示微信的新组件movable-view,因此选用了网络上使用view组件来实现的方案。

参考链接:https://blog.csdn.net/LiaoFengJi/article/details/105218664

提炼代码如下:

index.wxml
1
2
3
4
5
6
7
8
9
10
<view wx:for="{{dataList}}" data-index="{{index}}" class="item {{item.isTouchMove ? 'touch-move-active' : ''}}" bindtouchstart="touchStart" bindtouchmove="touchMove">
<!-- 这里原本bindtouchstart和bindtouchmove是放在内容的组件里(item-left),但因为我的按钮做得比较大所以设成了整个组件都可以滑动,使得整条内容上都可以右滑关闭菜单 -->
<view class="item-left" data-index="{{index}}">
<!-- 每条要显示的内容 -->
</view>
<view class="item-right">
<view class="btn-right" bindtap="setTopItem">置顶</view>
<view class="btn-right" bindtap="deleteItem">删除</view>
</view>
</view>
index.wxss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
.item {
display: flex;
}

/* 内容部分 */
.item-left {
width: 100%;
/*关键代码*/
margin-left: -400rpx; /*rpx根据需要调整,具体数值为按钮部分的宽度*/
transform: translateX(400rpx); /*rpx根据需要调整,具体数值为按钮部分的宽度*/
-webkit-transition: all 0.4s;
transition: all 0.4s;
-webkit-transform: translateX(400rpx); /*rpx根据需要调整,具体数值为按钮部分的宽度*/
/*关键代码*/
}

/* 按钮部分 */
.item-right {
height: 100%;
width: 400rpx; /*根据需要调整*/
display: flex;
flex-direction: row;
/*关键代码*/
transform: translateX(420rpx); /*rpx根据需要调整,具体数值为按钮部分的宽度多一些*/
-webkit-transition: all 0.4s;
transition: all 0.4s;
-webkit-transform: translateX(420rpx); /*rpx根据需要调整,具体数值为按钮部分的宽度多一些*/
/*关键代码*/
}

.btn-right {
width: 50%; /*这里根据自己的需要划成了两半*/
}

/* 向左滑动 */
.touch-move-active .item-left,
.touch-move-active .item-right {
/*关键代码*/
-webkit-transform: translateX(0);
transform: translateX(0);
/*关键代码*/
}
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* Page */
data: {
dataList: [/*存放的数据,每条中应有一个默认为false的属性isTouchMove*/],
startX: 0,// 设置开始的位置X
startY: 0,// 设置开始的位置Y
},

// 开始滑动
touchStart(e) {
let dataList = this.data.dataList;
dataList.forEach(item => {
// 让原先滑动的块隐藏
if (item.isTouchMove) {
item.isTouchMove = !item.isTouchMove;
}
});
this.setData({
dataList: dataList,
});
// 初始化开始位置
this.data.startX = e.touches[0].clientX;
this.data.startY = e.touches[0].clientY;
// 在参考代码中,这里全部都setData了,但实际上startX, Y属于没有涉及渲染的纯数据,尽量不要用setData
},
// 滑动的过程
touchMove(e) {
let moveX = e.changedTouches[0].clientX,
moveY = e.changedTouches[0].clientY,
curIndex = e.currentTarget.dataset.index,
//注意,wxml里面一定要设置data-index="{{index}}",这样e.currentTarget.dataset中才会传index的值
dataList = this.data.dataList,
// 拿到滑动的角度,判断是否大于 30°,若大于,则不滑动
angle = this.angle(
{ X: this.data.startX,
Y: this.data.startY
}, { X: moveX,
Y: moveY
}
);

dataList.forEach((item, index) => {
// 这里相对参考代码做了精炼
// 判断三个条件:遍历到的item是当前滑动的块,角度小于30度,滑动到的x坐标小于开始的x坐标(向左),均满足则判断为左滑
if (curIndex === index && angle < 30 && moveX < this.data.startX) {
item.isTouchMove = true;
} else {
item.isTouchMove = false; //否则右滑
}
});

this.setData({
dataList
});
},

/**
* 计算滑动角度
* @param {Object} start 起点坐标
* @param {Object} end 终点坐标
*/
angle: function (start, end) {
var _X = end.X - start.X,
_Y = end.Y - start.Y
//返回角度 /Math.atan()返回数字的反正切值
return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
},

// 删除
deleteItem(e) {
/* 这里是具体删除item的方法 */
}

实现效果

侧滑效果

结语

本次实践对参考代码并非完全照搬,而是根据实际使用的需求进行了调整,且对代码中的一些地方做了精炼和改良,是充满自己的理解的。实际使用时,我的内容条其实是包装在自定义组件中,而函数全部通过triggerEvent发送到页面js,在页面中执行(因为需要对每条数据的isTouchMove做更改)。但为了方便理解,在本页中依然采用全部在同一个页面上操作的方法来完成。

实际工程中,接下来还有更多的坑。当然,这些都是大前端开发跨平台APP的苦果,仅仅是参考微信小程序中的运用的可以忽略(貌似要使用movable-view也不难,js部分不带变的)。欲知后事如何,且听下回分解。