在 Uniapp 开发中,左滑显示编辑 / 删除按钮是移动端列表的常见交互需求,本文将基于实战场景,讲解如何实现「左滑显示操作按钮、默认隐藏」的列表效果,同时解决平板端适配、滑动误触、数据加载等核心问题。
注意:页面中有些简写样式是我自己封装的:比如h-146实际上就是.h-146{height:146rpx};有哪不明白的可以留下评论~
一、需求分析
本次实现的核心需求:
- 列表项默认只显示内容区域,编辑 / 删除按钮隐藏;
- 左滑列表项时显示操作按钮,右滑 / 点击其他项自动收起;
- 适配手机、iPad Pro 等多端设备,避免大屏布局错乱;
- 支持分页加载数据,操作按钮点击后有交互反馈。
二、核心实现思路
- 布局层 :使用
scroll-view的scroll-x实现横向滑动,操作按钮区固定宽度,默认在内容区右侧隐藏; - 交互层 :监听
touchstart/touchend事件,通过计算滑动距离判断滑动方向,控制scroll-left值显示 / 隐藏按钮; - 适配层:通过媒体查询和宽度限制,保证平板端布局和手机端一致;
- 数据层:实现分页加载,操作按钮点击后处理数据并更新视图。
三、完整代码实现
1. 模板结构(template)
html
<template>
<view>
<view class="overflow-hidden">
<block v-for="(item,index) in list" :key="index">
<scroll-view
class="scroll-view_H m-top-20"
scroll-x="true"
:scroll-left="item.scrollLeft"
@touchstart="touchStart($event,index)"
@touchend="touchEnd($event,index)"
scroll-with-animation="true"
:show-scrollbar="false"
>
<view class="scroll-view-item_H">
<view class="dis-flex ali-center ">
<!-- 内容展示区 -->
<view class="content h-146 dis-flex ali-center jus-spa back-white border-radius-12 " @tap="item.show_btn?showInfo(index):''">
<view class="w-620 dis-flex ali-center">
<image class="w-65 h-65 dis-block m-left-20" src="/static/grzx.png" mode=""></image>
<view class="m-left-20">
<view class="f-30 w-450 shenglue-11">
{{item.address}}
</view>
<view class="f-26 col-gray m-top-10 w-450">
{{item.name}} {{item.phone}}
</view>
</view>
</view>
<view class="w-90">
<view class="w-90 h-90 dis-flex ali-center jus-center">
<image class="w-25 h-24 dis-block" src="/static/images/my/bj.png" mode=""></image>
</view>
</view>
</view>
<!-- 操作按钮区:左滑显示 -->
<view class="w-160 m-left-20 dis-flex ali-center">
<view @touchstart="editItem(index)" class="w-80 h-80 back-white border-radius-50 dis-flex ali-center jus-center">
<image class="w-40 h-40 dis-block" src="/static/common/e_icon.svg" mode=""></image>
</view>
<view @touchstart="deleteItem(index)" class="w-80 h-80 back-white border-radius-50 dis-flex ali-center jus-center">
<image class="w-40 h-40 dis-block" src="/static/common/d_icon.svg" mode=""></image>
</view>
</view>
</view>
</view>
</scroll-view>
</block>
</view>
<view class="h-30"></view>
</view>
</template>
- 逻辑处理(script)
html
<script>
export default {
data() {
return {
touchStartX: 0, // 触屏起始X坐标
touchStartY: 0, // 触屏起始Y坐标
info: null, // 接口返回信息
list: [], // 列表数据
page: 1, // 分页页码
threshold: 50 // 滑动阈值(避免误触)
}
},
onLoad() {
this.page = 1;
this.initData(); // 初始化加载数据
},
onReachBottom() {
console.log('===触底加载下一页===');
this.page += 1;
this.initData();
},
methods: {
// 分页加载数据
initData(){
const that = this;
const url = 'employee/getList';
const data = { page: that.page };
// 异步请求(替换为自己的请求工具)
that.util.asynRequest(url, data, 'post',
function(res) {
if(that.util.isNonEmptyPlainObject(res.data) && Array.isArray(res.data.data) && res.data.data.length > 0){
that.info = res.data;
// 拼接分页数据,初始化scrollLeft(隐藏按钮)
const newData = res.data.data.map(item => ({
...item,
scrollLeft: 0,
show_btn: true
}));
that.list = that.list.concat(newData);
}else{
if(that.page > 1) that.page--;
that.util.showToast('暂无更多数据!');
}
},
function(err) {
console.error('请求失败:', err);
that.util.showToast(err.info);
if(that.page > 1) that.page--;
})
},
// 编辑操作
editItem(index){
const curItem = this.list[index];
uni.showToast({ title: `编辑${curItem.address}`, icon: 'none' });
// 编辑后收起按钮
curItem.scrollLeft = 0;
curItem.show_btn = true;
this.$forceUpdate();
},
// 删除操作
deleteItem(index){
const curItem = this.list[index];
uni.showModal({
title: '提示',
content: `确定要删除${curItem.address}吗?`,
success: (res) => {
if (res.confirm) {
this.list.splice(index, 1);
uni.showToast({ title: '删除成功', icon: 'success' });
}
}
});
},
// 触摸开始:记录起始坐标
touchStart(e,index) {
this.touchStartX = e.touches[0].clientX;
this.touchStartY = e.touches[0].clientY;
},
// 触摸结束:判断滑动方向,控制按钮显示/隐藏
touchEnd(e,index) {
const deltaX = e.changedTouches[0].clientX - this.touchStartX;
const deltaY = e.changedTouches[0].clientY - this.touchStartY;
// 收起其他所有项的按钮(保证同时只展开一个)
this.list.forEach((item, i) => {
if(i !== index){
item.scrollLeft = 0;
item.show_btn = true;
}
});
// 只处理水平滑动(过滤上下滑动)
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > this.threshold) {
if (deltaX > 0) {
// 右滑:隐藏按钮
this.list[index].scrollLeft = 0;
this.list[index].show_btn = true;
} else {
// 左滑:显示按钮(按钮总宽度360rpx)
this.list[index].scrollLeft = 360;
this.list[index].show_btn = false;
}
}
this.$forceUpdate();
},
}
}
</script>
- 样式适配(style)
html
<style>
page{
background: #F6F6F6;
padding: 0rpx 5rpx 20rpx 20rpx;
box-sizing: border-box;
}
.scroll-view_H{
white-space: nowrap;
}
/* 平板端适配:限制内容区宽度 */
@media screen and (min-width:900rpx) {
.content {
width: calc(750rpx - 35rpx);
}
}
.scroll-view-item_H {
display: inline-block;
}
/* 隐藏滚动条(多端兼容) */
/* #ifdef MP-WEIXIN || APP-PLUS */
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* #endif */
/* #ifdef H5 */
uni-scroll-view .uni-scroll-view::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
}
scroll-view ::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
}
/* #endif */
/* 按钮样式 */
.w-80 {
width: 80rpx !important;
}
</style>
四、核心知识点解析
1. 滑动交互核心
- 滑动方向判断 :通过
touchstart和touchend的坐标差deltaX判断左右滑,deltaY过滤上下滑动误触; - 滑动阈值 :设置
threshold: 50,只有滑动距离超过 50px 才触发操作,避免手指轻微滑动导致的误操作; - scroll-left 控制 :默认
scrollLeft: 0(隐藏按钮),左滑后设为按钮总宽度(显示按钮),结合scroll-with-animation实现平滑滑动。
2. 多端适配技巧
- 平板端宽度限制 :通过媒体查询
@media screen and (min-width:900rpx)固定内容区宽度,避免 iPad 等大屏设备布局拉伸; - 滚动条隐藏:区分小程序 / APP/H5 不同环境,通过 CSS 隐藏横向滚动条,保证视觉统一;
- rpx 单位:全程使用 rpx 作为尺寸单位,自动适配不同屏幕分辨率。
3. 数据处理要点
- 分页加载 :
onReachBottom监听触底事件,拼接新数据时初始化scrollLeft,避免新数据默认显示按钮; - 操作后视图更新 :编辑 / 删除后通过
$forceUpdate()强制更新视图,保证按钮状态同步; - 删除二次确认 :使用
uni.showModal做删除确认,提升用户体验。
五、常见问题及解决方案
问题 1:左滑不显示按钮 / 按钮直接展示
- 原因:
scrollLeft值设置错误,或按钮区宽度与scrollLeft不匹配; - 解决:确保
scrollLeft值等于操作按钮区总宽度,且内容区宽度覆盖按钮区(默认隐藏)。
问题 2:平板端布局错乱
- 原因:大屏设备下内容区无限拉伸,按钮位置偏移;
- 解决:通过媒体查询固定内容区最大宽度,或给
scroll-view设置max-width: 750rpx; margin: 0 auto;。
问题 3:滑动时多个列表项同时展开
- 原因:未处理其他项的
scrollLeft状态; - 解决:在
touchEnd中遍历列表,将非当前项的scrollLeft重置为 0。
六、总结
本文实现的 Uniapp 左滑列表,核心是通过scroll-view横向滑动 + 触摸事件监听,结合多端适配技巧,实现了「左滑显示操作按钮、默认隐藏」的交互效果,同时支持分页加载、操作反馈等实战需求。
关键要点:
- 滑动阈值过滤误触,保证交互稳定性;
- 统一控制
scrollLeft状态,避免多列展开; - 媒体查询 + rpx 单位实现多端适配;
- 分页数据加载时初始化按钮状态。
该方案可直接应用于地址管理、员工管理、订单列表等场景,稍作修改即可适配不同 UI 设计需求。