当前位置:首页 > 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组件传值实现分页

vue组件传值实现分页

Vue 组件传值实现分页 在Vue中实现分页功能,通常需要父子组件之间的数据传递。以下是几种常见的传值方法: 使用props和$emit 父组件通过props向子组件传递数据,子组件通过$emit向…

vue radio组件实现

vue radio组件实现

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

vue实现递归组件

vue实现递归组件

递归组件的实现方法 在Vue中实现递归组件主要依靠组件调用自身的能力。以下是几种常见的实现方式: 使用组件name属性 通过组件的name属性实现递归调用是最简单的方式: <template…

vue组件实现vmodel

vue组件实现vmodel

Vue 组件实现 v-model 在 Vue 中,v-model 是双向数据绑定的语法糖,默认情况下绑定 value 属性并监听 input 事件。在自定义组件中实现 v-model 需要正确配置 p…

vue 实现树组件

vue 实现树组件

Vue 树形组件实现 基础树形结构实现 使用递归组件实现树形结构,核心是通过组件自身调用自身渲染嵌套数据。 <template> <ul> <li v-fo…

vue实现组件刷新

vue实现组件刷新

强制重新渲染组件 使用 this.$forceUpdate() 方法可以强制 Vue 实例重新渲染,但不会更新子组件。适用于依赖非响应式数据的情况。 methods: { refreshComp…