右滑编辑列表项时如何防止内容被意外选中?

Code°美蓝 阅读 10

我在做移动端的待办事项列表,想实现右滑出现“编辑”按钮的效果。但手指滑动时经常误触选中文本,体验很糟。

试过加 user-select: none,但只对静态内容有效,滑出的按钮还是会触发选择。是不是得配合 JS 阻止默认行为?或者我的 CSS 写法有问题?

.swipe-item {
  position: relative;
  overflow: hidden;
}
.swipe-content {
  background: white;
  transition: transform 0.3s;
}
.swipe-actions {
  position: absolute;
  right: 0;
  top: 0;
  width: 60px;
  background: #f44;
}
我来解答 赞 1 收藏
二维码
手机扫码查看
2 条解答
Tr° 素玲
这个问题我之前踩过坑,主要是 touch 事件触发时浏览器的默认选择行为没处理好。

你的 user-select: none 思路是对的,但问题在于它只作用于静态渲染,滑动过程中动态变化的元素还是会触发选择。需要配合 JS 在滑动时主动阻止。

核心解决方案有两个点:

第一,给滑动容器加上 touch-action: pan-x,告诉浏览器这个区域只允许水平滑动,禁用默认的选中文本、长按菜单等行为。

第二,在 touchstart 和 touchmove 里调用 preventDefault(),但要注意别把滚动也干掉了。

给你一段能用的代码:

.swipe-item {
position: relative;
overflow: hidden;
touch-action: pan-x pan-y;
}
.swipe-content {
background: white;
transition: transform 0.3s;
user-select: none;
-webkit-user-select: none;
}
.swipe-actions {
position: absolute;
right: 0;
top: 0;
width: 60px;
background: #f44;
user-select: none;
-webkit-user-select: none;
}


const swipeContent = document.querySelector('.swipe-content');
let startX = 0;
let isSwiping = false;

swipeContent.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
isSwiping = false;
}, { passive: true });

swipeContent.addEventListener('touchmove', (e) => {
const currentX = e.touches[0].clientX;
const diff = currentX - startX;

if (Math.abs(diff) > 10) {
isSwiping = true;
e.preventDefault();
}
}, { passive: false });

swipeContent.addEventListener('touchend', () => {
isSwiping = false;
});


关键点是 touchmove 里的 { passive: false },不然 preventDefault() 不生效。加个阈值判断,水平移动超过 10px 才认为是滑动,避免影响正常的点击操作。

调试看看,应该就不会再误选中文字了。
点赞
2026-03-02 13:00
心虹酱~
你这个问题我遇到过,就是滑动时选中区域没控制好,按规范得两层防护:一层 CSS 防静态选中,一层 JS 防手势选中。

先看你的 CSS,user-select: none 要加在能触发滑动的整个容器上,不只是内容区域,包括滑出的按钮区域,不然按钮一旦被手指划到还是会选中。建议这样写:

.swipe-item,
.swipe-content,
.swipe-actions,
.swipe-actions button {
user-select: none;
-webkit-user-select: none;
}


但光这样还不够,因为移动端浏览器在滑动手势中默认会尝试选中文本,尤其是手指稍微带一点停顿或者划过文字区域时。所以还得配合 JS 把 touchstarttouchmove 的默认行为拦住,只在你真正需要滑动的元素上加这个:

const swipeItem = document.querySelector('.swipe-item');
swipeItem.addEventListener('touchstart', (e) => {
e.preventDefault();
}, { passive: false });

swipeItem.addEventListener('touchmove', (e) => {
e.preventDefault();
}, { passive: false });


注意 passive: false 必须显式声明,不然浏览器默认是 passive true,preventDefault() 会被忽略,这是规范里写的。
别嫌麻烦,很多移动端问题都是因为 passive 事件监听没设对,我之前也踩过这坑,调试好久才发现是浏览器悄悄吞了 preventDefault()

如果用的是框架(比如 Vue 或 React),记得在组件卸载时移除监听,不然内存泄漏和事件冲突会很头疼。
点赞 1
2026-02-25 17:04