最近使用uniapp做一些小程序的功能;需要在列表项中左滑实现菜单功能,之前没有什么经验,所以参考网上的各种文章最终才实现的功能;这里记录一下实现过程;
先看视图页面:
<scroll-view v-if="myCustomerList.length!=0" :style="'height:'+ height" scroll-y lower-threshold="30" @scrolltolower="LoadMoreMyCustomers"> <view v-for="(item,index) in myCustomerList" :key="index" class="touch-item" :class="item.IsTouchMove?'touch-move-active':''" :data-index="index" @touchstart="touchStartMyItem" @touchmove="touchMoveMyItem"> <view class="itemcontent"> ...... </view> <view class="itembtn" style="background-color: red;">删除</view> </view> </scroll-view>
上边的代码就是列表的基本界面代码,其中主要有几个点需要注意:
1、IsTouchMove是判断当前项已经左滑,在获得到列表后首先要给每一项添加这个属性默认值为false
2、touchstart和touchmove是拖动单个项的关键事件
3、class="touch-item"是单个项的样式,需要注意的是touch-move-active样式是当IsTouchMove时才需要设置的,否则不设置;
4、class="itemcontent"是内容样式
5、class="itembtn"是左滑后显示的菜单样式
内容和菜单需要平级
下边再看下样式部分:
.touch-item { background-color: #F8F9FC; display: flex; justify-content: space-between; width: 100%; overflow: hidden } .itemcontent { display: flex; flex-direction: column; padding: 5px 10px; border-bottom: 1px solid #eeeeee; margin-right: 0; margin-left: -100px; width: 100%; -webkit-transition: all 0.4s; transition: all 0.4s; -webkit-transform: translateX(100px); transform: translateX(100px); position: relative; } .itembtn { width: 100px; display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: #119bf8; color: white; position: relative; -webkit-transform: translateX(100px); transform: translateX(100px); -webkit-transition: all 0.4s; transition: all 0.4s; } .touch-move-active .itemcontent, .touch-move-active .itembtn { -webkit-transform: translateX(0); transform: translateX(0); }
样式部分注意点:
1、需要设置单个项的宽度为100%,禁止滚动;
2、itemcontent的margin-left为负值,绝对值和itembtn的宽度要一致;并且itemcontent的宽度要默认为width: 100%,这样才能默认占满整行;
3、itemcontent和itembtn的translateX都是itembtn的宽度
最后看下实现逻辑:
touchStartMyItem(e) { this.myCustomerList.forEach(item => { if (item.IsTouchMove) { item.IsTouchMove = false; } this.startX = e.changedTouches[0].clientX; this.startY = e.changedTouches[0].clientY; }) }, touchMoveMyItem(e) { let that = this; let index = e.currentTarget.dataset.index; //当前索引 let startX = that.startX; //开始X坐标 let startY = that.startY; //开始Y坐标 let touchMoveX = e.changedTouches[0].clientX; //滑动变化坐标 let touchMoveY = e.changedTouches[0].clientY; //滑动变化坐标 //获取滑动角度 let angle = that.angle({ X: startX, Y: startY }, { X: touchMoveX, Y: touchMoveY });
/滑动超过30度角 return if (Math.abs(angle) > 30) return;
that.myCustomerList.forEach((element, i) => { element.IsTouchMove = false if (i == index) { if (touchMoveX > startX) { //右滑 element.IsTouchMove = false; } else { //左滑 element.IsTouchMove = true; } } }) }, 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); }
这两个方法就是核心的左滑方法,是网上找的内容,具体哪个网站忘了;我把循环稍作修改;
angle方法是计算滑动角度的方法,防止误操作;
原理就是滑动开始时,先循环将所有项设置为默认状态,然后记录当前项的坐标值;
在滑动时获得当前坐标,计算滑动角度,大于30度直接返回;然后循环找到对应item,根据滑动后的x值和滑动开始时x值之间的关系确定是左滑还是右滑,最后修改对应属性值;