You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Web应用中实现滑动删除组件的技术求助

React Web应用中实现滑动删除组件的技术求助

Hey there! 我懂你想要的那种拖动列表项向右滑出删除提示的效果——之前试了react swipeable和Swiper都没解决的话,咱们可以自己基于React的状态和原生事件监听来实现,完全能贴合你的需求,而且可控性更强。

下面我给你一个完整的自定义实现方案,核心思路是:

  • 用两层结构:底层是带红色背景和“DELETE ITEM”的删除提示层,上层是你的ItemContainer内容层
  • 监听鼠标/触摸事件,跟踪拖动的距离,动态改变内容层的位置
  • 拖动到一定阈值后触发删除逻辑,否则复位

完整代码实现

import React, { useState, useRef, useEffect } from 'react';

const SwipeToDelete = ({ children, onDelete }) => {
  // 跟踪拖动状态和距离
  const [isDragging, setIsDragging] = useState(false);
  const [dragX, setDragX] = useState(0);
  const [startX, setStartX] = useState(0);
  
  // 引用内容容器,获取它的宽度
  const contentRef = useRef(null);
  let contentWidth = 0;

  // 初始化获取容器宽度
  useEffect(() => {
    if (contentRef.current) {
      contentWidth = contentRef.current.offsetWidth;
    }
  }, []);

  // 处理拖动开始(兼容鼠标和触摸)
  const handleStart = (e) => {
    setIsDragging(true);
    const clientX = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX;
    setStartX(clientX);
  };

  // 处理拖动过程
  const handleMove = (e) => {
    if (!isDragging) return;
    const clientX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX;
    const newDragX = startX - clientX;
    // 限制拖动范围:只能向右拖,最大距离等于容器宽度
    const clampedDragX = Math.max(0, Math.min(newDragX, contentWidth));
    setDragX(clampedDragX);
  };

  // 处理拖动结束
  const handleEnd = () => {
    setIsDragging(false);
    // 设定阈值:拖动超过容器宽度的50%就触发删除
    if (dragX > contentWidth * 0.5) {
      onDelete();
    } else {
      // 否则复位
      setDragX(0);
    }
  };

  return (
    <div style={{ position: 'relative', overflow: 'hidden', margin: '8px 0' }}>
      {/* 底层删除提示层 */}
      <div 
        style={{
          position: 'absolute',
          top: 0,
          right: 0,
          width: '100%',
          height: '100%',
          backgroundColor: '#dc2626',
          display: 'flex',
          justifyContent: 'flex-end',
          alignItems: 'center',
          paddingRight: '16px',
          color: 'white',
          fontWeight: 'bold'
        }}
      >
        DELETE ITEM
      </div>
      {/* 上层内容容器(你的ItemContainer) */}
      <div
        ref={contentRef}
        style={{
          position: 'relative',
          backgroundColor: 'white',
          transform: `translateX(-${dragX}px)`,
          transition: isDragging ? 'none' : 'transform 0.2s ease',
          cursor: 'grab'
        }}
        onMouseDown={handleStart}
        onMouseMove={handleMove}
        onMouseUp={handleEnd}
        onMouseLeave={handleEnd}
        onTouchStart={handleStart}
        onTouchMove={handleMove}
        onTouchEnd={handleEnd}
      >
        {children}
      </div>
    </div>
  );
};

// 用法示例
const App = () => {
  const [items, setItems] = useState([
    { id: 1, content: '列表项1' },
    { id: 2, content: '列表项2' },
    { id: 3, content: '列表项3' }
  ]);

  const handleDelete = (itemId) => {
    setItems(items.filter(item => item.id !== itemId));
  };

  return (
    <div style={{ maxWidth: '400px', margin: '20px auto' }}>
      {items.map(item => (
        <SwipeToDelete key={item.id} onDelete={() => handleDelete(item.id)}>
          {/* 这里替换成你的ItemContainer内容 */}
          <div style={{ padding: '16px', borderBottom: '1px solid #eee' }}>
            {item.content}
          </div>
        </SwipeToDelete>
      ))}
    </div>
  );
};

export default App;

关键细节说明

  • 跨端兼容:同时监听了鼠标事件(桌面端)和触摸事件(移动端),确保在不同设备上都能正常工作
  • 拖动边界控制:限制拖动距离只能在0到内容容器宽度之间,避免过度拖动
  • 平滑过渡:拖动过程中关闭过渡动画保证流畅,结束时开启过渡实现复位/删除的平滑效果
  • 删除阈值:设置了50%的宽度阈值,你可以根据需求调整这个比例

你只需要把示例中<div style={{ padding: '16px', ... }}>{item.content}</div>替换成你自己的ItemContainer组件即可,完全能满足你“拖动ItemContainer显示右侧红色背景+DELETE ITEM文字”的需求。

备注:内容来源于stack exchange,提问作者Mark_Revans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 14:18:06