欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

react中实现可拖动div

程序员文章站 2022-05-01 20:46:56
把拖动div功能用react封装成class,在页面直接引入该class即可使用。 title为可拖动区域。panel为要实现拖动的容器。 优化了拖动框超出页面范围的情况,也优化了拖动太快时鼠标超出可拖动区域的情况,优化了拖动会卡顿的情况。 页面中添加引入方法:

把拖动div功能用react封装成class,在页面直接引入该class即可使用。

title为可拖动区域。panel为要实现拖动的容器。

优化了拖动框超出页面范围的情况,也优化了拖动太快时鼠标超出可拖动区域的情况,优化了拖动会卡顿的情况。

 

页面中添加引入方法:

<draggable panelid="要拖动容器的id" titleid="容器内标题的id" contentid="容器内除标题外的其他部分id" setpanelposition={this.setpanelposition.bind(this)}/>

页面中添加拖拽回调函数

  //推拽回调函数
  setpanelposition(left,top){
    this.setstate({pagex: left, pagey: top})
  }

要拖动的div如下:

<div id="要拖动的id" style={{left:this.state.pagex,top:this.state.pagey}}></div>

 

封装的class代码:

import react from 'react';
class draggable extends react.component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }
  //拖拽
  initdrag(){
    let {panelid,titleid,contentid} = this.props;
    this.paneldom = document.getelementbyid(panelid);
    this.titledom = document.getelementbyid(titleid);
    this.contentdom = document.getelementbyid(contentid);
    this.backgrounddom = document.body;
    this.bindevent();
  }

  //region event
  componentdidmount() {
    this.initdrag();
  }
  bindevent(){
    this.titledom.onmousedown = this.onmousedown.bind(this);
    this.titledom.onmouseup = this.onmouseup.bind(this);
    this.titledom.onmousemove = this.onmousemove.bind(this);

    this.contentdom.onmouseup = this.oncontentmouseup.bind(this);
    this.contentdom.onmousemove = this.oncontentmousemove.bind(this);

    this.backgrounddom.onmouseup = this.onbackgroundmouseup.bind(this);
    this.backgrounddom.onmousemove = this.onbackgroundmousemove.bind(this);
    let step = ()=>{
      this.activeanimation = true;
      window.requestanimationframe(step);
    };
    window.requestanimationframe(step);
  }

  /**
   * 鼠标按下,设置modal状态为可移动,并注册鼠标移动事件
   * 计算鼠标按下时,指针所在位置与modal位置以及两者的差值
   **/
  onmousedown (e) {
    const position = this.getposition(e)
    this.setstate({moving: true, diffx: position.diffx, diffy: position.diffy})
  }

  // 松开鼠标,设置modal状态为不可移动
  onmouseup (e) {
    const { moving } = this.state
    moving && this.setstate({moving: false});
  }

  // 鼠标移动重新设置modal的位置
  onmousemove (e) {
    const {moving, diffx, diffy} = this.state
    if (moving) {
      if(this.activeanimation){
        // 获取鼠标位置数据
        const position = this.getposition(e)
        // 计算modal应该随鼠标移动到的坐标
        const x = position.mousex - diffx
        const y = position.mousey - diffy
        // 窗口大小,结构限制,需要做调整,减去侧边栏宽度
        const { clientwidth, clientheight } = document.documentelement
        const modal = this.paneldom
        if (modal) {
          // 计算modal坐标的最大值
          const maxheight = clientheight - modal.offsetheight
          const maxwidth = clientwidth - modal.offsetwidth
          // 判断得出modal的最终位置,不得超出浏览器可见窗口
          const left = x > 0 ? (x < maxwidth ? x : maxwidth) : 0
          const top = y > 0 ? (y < maxheight ? y : maxheight) : 0
          if(this.props.setpanelposition){
            this.props.setpanelposition(left,top);
          }
        }
        this.activeanimation = false;
      }
    }
  }
  oncontentmousemove(e){
    let obj = {};
    obj.target = this.titledom;
    obj.pagex = e.pagex;
    obj.screeny = e.screeny;
    this.onmousemove(obj);
  }
  oncontentmouseup(){
    this.onmouseup();
  }
  onbackgroundmousemove(e){
    let obj = {};
    obj.target = this.titledom;
    obj.pagex = e.pagex;
    obj.screeny = e.screeny;
    this.onmousemove(obj);
  }
  onbackgroundmouseup(){
    this.onmouseup();
  }
  //endregion

  //region request
  // 获取鼠标点击title时的坐标、title的坐标以及两者的位移
  getposition (e) {
    // 标题dom元素titledom
    const titledom = e.target
    // titledom的坐标(视窗)
    const x = titledom.getboundingclientrect().left
    // 由于y轴出现滚动条,需要与鼠标保持一致,存储页面相对位置
    const y = this.paneldom.offsettop

    // 鼠标点击的坐标(页面)
    let mousex = e.pagex
    let mousey = e.screeny
    // 鼠标点击位置与modal的位移
    const diffx = mousex - x
    const diffy = mousey - y
    return {x, y, mousex, mousey, diffx, diffy}
  }
  //endregion

  //region render
  //endregion

  //region clear
  //endregion

  render() {
    return (
      <>
      </>
    );
  }
}
export default draggable;