当前位置:首页 > 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;

支持触摸事件

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

react高阶组件实现拖拽

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);
};

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

react高阶组件实现拖拽

<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
      }
    });
  });
};

边界限制

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

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实现拖拽实现组件嵌套

vue实现拖拽实现组件嵌套

Vue 拖拽实现组件嵌套 使用 Vue 实现拖拽组件嵌套功能可以通过原生 HTML5 拖拽 API 或第三方库如 vuedraggable 实现。以下是两种方法的详细说明: 使用 HTML5 拖拽…

vue如何实现目录组件

vue如何实现目录组件

实现目录组件的基本思路 在Vue中实现目录组件通常需要结合页面内容的结构化数据(如标题层级),通过动态渲染生成可交互的目录。核心步骤包括提取标题、生成目录结构、实现滚动联动等。 提取标题信息 通过d…

vue组件实现

vue组件实现

Vue 组件实现 Vue 组件是 Vue.js 的核心特性之一,允许开发者将 UI 拆分为独立、可复用的模块。以下是实现 Vue 组件的几种常见方式: 单文件组件(SFC) 单文件组件是 Vue…

vue VUE实现日历组件功能

vue VUE实现日历组件功能

Vue 日历组件实现方法 基础日历结构 使用Vue的模板语法构建日历的HTML结构,通常包含头部(年月显示、切换按钮)和日历表格(星期标题和日期格子)。 <template> <…

vue实现tooltips组件

vue实现tooltips组件

实现基础 Tooltip 组件 创建一个名为 Tooltip.vue 的单文件组件,包含模板、样式和逻辑: <template> <div class="tooltip-co…

vue table组件实现

vue table组件实现

Vue 表格组件实现方案 基础表格实现 使用<table>标签结合v-for指令渲染数据是最简单的实现方式: <template> <table>…