当前位置:首页 > React

react高阶组件实现拖拽

2026-01-27 10:04:19React

实现拖拽功能的高阶组件

在React中,可以通过高阶组件(HOC)封装拖拽逻辑,使得被包裹的组件具备拖拽能力。以下是一个实现拖拽功能的HOC示例:

创建高阶组件

import React, { Component } from 'react';

const withDragAndDrop = (WrappedComponent) => {
  return class extends Component {
    state = {
      isDragging: false,
      position: { x: 0, y: 0 },
      dragStart: { x: 0, y: 0 }
    };

    handleMouseDown = (e) => {
      this.setState({
        isDragging: true,
        dragStart: {
          x: e.clientX - this.state.position.x,
          y: e.clientY - this.state.position.y
        }
      });
      document.addEventListener('mousemove', this.handleMouseMove);
      document.addEventListener('mouseup', this.handleMouseUp);
    };

    handleMouseMove = (e) => {
      if (!this.state.isDragging) return;
      this.setState({
        position: {
          x: e.clientX - this.state.dragStart.x,
          y: e.clientY - this.state.dragStart.y
        }
      });
    };

    handleMouseUp = () => {
      this.setState({ isDragging: false });
      document.removeEventListener('mousemove', this.handleMouseMove);
      document.removeEventListener('mouseup', this.handleMouseUp);
    };

    componentWillUnmount() {
      document.removeEventListener('mousemove', this.handleMouseMove);
      document.removeEventListener('mouseup', this.handleMouseUp);
    }

    render() {
      const { position } = this.state;
      return (
        <div
          style={{
            position: 'absolute',
            left: `${position.x}px`,
            top: `${position.y}px`,
            cursor: this.state.isDragging ? 'grabbing' : 'grab'
          }}
          onMouseDown={this.handleMouseDown}
        >
          <WrappedComponent {...this.props} />
        </div>
      );
    }
  };
};

使用高阶组件

const Box = () => {
  return (
    <div style={{
      width: '100px',
      height: '100px',
      backgroundColor: 'blue'
    }} />
  );
};

const DraggableBox = withDragAndDrop(Box);

function App() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <DraggableBox />
    </div>
  );
}

export default App;

支持触摸事件

为了在移动设备上也能使用,可以添加触摸事件支持:

handleTouchStart = (e) => {
  const touch = e.touches[0];
  this.setState({
    isDragging: true,
    dragStart: {
      x: touch.clientX - this.state.position.x,
      y: touch.clientY - this.state.position.y
    }
  });
  document.addEventListener('touchmove', this.handleTouchMove);
  document.addEventListener('touchend', this.handleTouchEnd);
};

handleTouchMove = (e) => {
  if (!this.state.isDragging) return;
  const touch = e.touches[0];
  this.setState({
    position: {
      x: touch.clientX - this.state.dragStart.x,
      y: touch.clientY - this.state.dragStart.y
    }
  });
};

handleTouchEnd = () => {
  this.setState({ isDragging: false });
  document.removeEventListener('touchmove', this.handleTouchMove);
  document.removeEventListener('touchend', this.handleTouchEnd);
};

然后在渲染方法中添加触摸事件处理器:

<div
  // ...其他属性
  onTouchStart={this.handleTouchStart}
>
  <WrappedComponent {...this.props} />
</div>

性能优化

对于频繁的拖拽操作,可以使用requestAnimationFrame优化性能:

handleMouseMove = (e) => {
  if (!this.state.isDragging) return;
  requestAnimationFrame(() => {
    this.setState({
      position: {
        x: e.clientX - this.state.dragStart.x,
        y: e.clientY - this.state.dragStart.y
      }
    });
  });
};

边界限制

可以添加边界限制,防止元素被拖出可视区域:

react高阶组件实现拖拽

handleMouseMove = (e) => {
  if (!this.state.isDragging) return;

  let newX = e.clientX - this.state.dragStart.x;
  let newY = e.clientY - this.state.dragStart.y;

  // 限制在窗口范围内
  newX = Math.max(0, Math.min(newX, window.innerWidth - 100));
  newY = Math.max(0, Math.min(newY, window.innerHeight - 100));

  this.setState({
    position: { x: newX, y: newY }
  });
};

这个高阶组件提供了基本的拖拽功能,可以根据需要进一步扩展,如添加拖拽限制、拖拽手柄或与其他组件的交互逻辑。

标签: 高阶组件
分享给朋友:

相关文章

vue实现tooltips组件

vue实现tooltips组件

Vue实现Tooltips组件的方法 基础实现:使用Vue指令 创建一个自定义指令v-tooltip,通过鼠标事件触发提示框的显示与隐藏。 Vue.directive('tooltip', {…

vue实现组件循环图片

vue实现组件循环图片

Vue 实现组件循环图片的方法 在 Vue 中实现组件循环图片通常可以通过 v-for 指令结合动态数据绑定完成。以下是几种常见的实现方式: 使用静态图片路径数组 假设有一组本地图片路径,可以通过数…

vue实现组件

vue实现组件

Vue 实现组件的方法 Vue 中实现组件可以通过多种方式,包括全局注册、局部注册、单文件组件(SFC)等。以下是常见的实现方法。 全局注册组件 全局注册的组件可以在任何 Vue 实例或组件中使用。…

vue轮播组件实现

vue轮播组件实现

vue轮播组件实现方法 使用第三方库(如Swiper) 安装Swiper库: npm install swiper 在Vue组件中引入: <template> <div cl…

如何设计react组件

如何设计react组件

设计 React 组件的核心原则 React 组件的设计需要遵循高内聚、低耦合的原则,确保组件功能独立且易于维护。组件的设计可以分为展示组件和容器组件两类,展示组件负责 UI 渲染,容器组件负责逻辑处…

vue radio组件实现

vue radio组件实现

Vue Radio 组件实现 在 Vue 中实现 Radio 组件可以通过原生 HTML 的 <input type="radio"> 结合 Vue 的响应式特性来完成。以下是几种常见的实…