当光标离开div区域时元素停止拖动

时间:2019-04-11 07:25:56

标签: javascript css reactjs draggable

我一直在尝试在react中实现可拖动的div,基本上,如果我在移动设备上,我会使用鼠标来点击并拖动元素,甚至是手指。 问题是,当我将鼠标移得太快并且光标离开div的区域时,该元素停止了拖动。就像我没有足够快地更新div的位置以跟上光标速度。 知道如何解决这个问题吗?

我也一直在使用顶部和左侧位置来更新div的位置,而使用CSS translatex / y会有任何优势吗? 有什么不同?

import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';

class App extends Component {
  constructor() {
    super();
    this.state = {
      pos: {
        x:0,
        y:0,
      },
      rel: {
        x:0,
        y:0
      },
      dragging : false
    };
    this.draggable = React.createRef()
  }

  onTouchStart = e => {
    const touch = e.touches[0]
    const posTop = this.draggable.current.offsetTop
    const posLeft = this.draggable.current.offsetLeft

    this.setState({
      dragging: true,
      rel: {
        x: touch.clientX - posLeft,
        y: touch.clientY - posLeft
      }
    })
    e.stopPropagation()
  }

  onTouchMove = e => {
    if (!this.state.dragging) return
    const touch = e.touches[0]
    this.setState({
      pos: {
        x: touch.clientX - this.state.rel.x,
        y: touch.clientY - this.state.rel.y
      }

    })
    e.stopPropagation()
    e.preventDefault()
  }

  onTouchEnd = e => {
    this.setState({dragging: false})

  }

  onMouseDown =  (e) => {
    // only left mouse button
    if (e.button !== 0) return
    const posTop = this.draggable.current.offsetTop
    const posLeft = this.draggable.current.offsetLeft
    console.log(e.pageX,': pagex   ', e.pageY, ' : and pagey')
    console.log(posTop, ': posTop', posLeft, ' : posY')
    console.log('resultLeft :', e.pageX - posLeft, 'resultTop  :',  e.pageY - posTop)
    this.setState({
      dragging: true,
      rel: {
        x: e.pageX - posLeft,
        y: e.pageY - posTop
      }     
    })
    e.stopPropagation()
    e.preventDefault()
  }

  onMouseUp =  (e)  => {
    this.setState({dragging: false})
    e.stopPropagation()
    e.preventDefault()
  }

  onMouseMove = (e) => {
    if (!this.state.dragging) return
    this.setState({
      pos: {
        x: e.pageX - this.state.rel.x,
        y: e.pageY - this.state.rel.y    
      }        
    })
    e.stopPropagation()
    e.preventDefault()
  }

  render() {
    return (
      <div style={{position:'relative', backgroundColor:'green', height:'100%', width:'100%'}}>
          <div style={{position:'absolute',backgroundColor:'red',
          height: '100px', width:'100px',
           left: this.state.pos.x + 'px', top: this.state.pos.y + 'px'}}
           onTouchStart={this.onTouchStart}
           onTouchMove={this.onMouseMove}
           onTouchEnd={this.onTouchEnd}
            onMouseDown={this.onMouseDown}
            onTouchMove={this.onTouchMove}
            onMouseMove={this.onMouseMove}
            onMouseUp={this.onMouseUp}
            ref={this.draggable}
          > draggable div 
        </div>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

您可以将代码放在stackblitz上,它可以工作,因此可以尝试。 任何建议都值得欢迎!

Stackblitz链接:https://stackblitz.com/edit/react-draggable-test-oezlsk

1 个答案:

答案 0 :(得分:0)

好吧, 找出问题所在。 我将事件onMouseUp onMouseMove分配给div而不是父亲。 此外,由于根div没有任何尺寸,父亲的身高和宽度也不适当。

更新后的有效代码如下

import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';

class App extends Component {
  constructor() {
    super();
    this.state = {
      pos: {
        x:0,
        y:0,
      },
      rel: {
        x:0,
        y:0
      },
      dragging : false
    };
    this.draggable = React.createRef()
  }

  onTouchStart = e => {
    const touch = e.touches[0]
    const posTop = this.draggable.current.offsetTop
    const posLeft = this.draggable.current.offsetLeft

    this.setState({
      dragging: true,
      rel: {
        x: touch.clientX - posLeft,
        y: touch.clientY - posLeft
      }
    })
    e.stopPropagation()
  }

  onTouchMove = e => {
    if (!this.state.dragging) return
    const touch = e.touches[0]
    this.setState({
      pos: {
        x: touch.clientX - this.state.rel.x,
        y: touch.clientY - this.state.rel.y
      }

    })
    e.stopPropagation()
    e.preventDefault()
  }

  onTouchEnd = e => {
    this.setState({dragging: false})

  }

  onMouseDown =  (e) => {
    // only left mouse button
    if (e.button !== 0) return
    const posTop = this.draggable.current.offsetTop
    const posLeft = this.draggable.current.offsetLeft
    console.log(e.pageX,': pagex   ', e.pageY, ' : and pagey')
    console.log(posTop, ': posTop', posLeft, ' : posY')
    console.log('resultLeft :', e.pageX - posLeft, 'resultTop  :',  e.pageY - posTop)
    this.setState({
      dragging: true,
      rel: {
        x: e.pageX - posLeft,
        y: e.pageY - posTop
      }     
    })
    e.stopPropagation()
    e.preventDefault()
  }

  onMouseUp =  (e)  => {
    this.setState({dragging: false})
    e.stopPropagation()
    e.preventDefault()
  }

  onMouseMove = (e) => {
    if (!this.state.dragging) return
    this.setState({
      pos: {
        x: e.pageX - this.state.rel.x,
        y: e.pageY - this.state.rel.y    
      }        
    })
    e.stopPropagation()
    e.preventDefault()
  }

  render() {
    return (
      <div onMouseUp={this.onMouseUp} onMouseMove={this.onMouseMove} style={{position:'relative', backgroundColor:'green', height:'120%', width:'120%'}}>
          <div style={{position:'absolute',backgroundColor:'red',
          height: '100px', width:'100px',
           left: this.state.pos.x + 'px', top: this.state.pos.y + 'px'}}
           onTouchStart={this.onTouchStart}
           onTouchMove={this.onMouseMove}
           onTouchEnd={this.onTouchEnd}
            onMouseDown={this.onMouseDown}
            onTouchMove={this.onTouchMove}          

            ref={this.draggable}
          > draggable div 
        </div>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));