如何将 React.createclass 转换为 Class 组件?

How Can I convert React.createclass to Class Component?

我在react js中举了一个例子,拖动某些div从这里 http://jsfiddle.net/Af9Jt/2/

现在它在 createClass 中,我需要将其转换为 class Draggable extends React.Component 以便将其导出到另一个组件中。这是代码

APP.JS


import React from 'react';
import './App.css';
import Draggable from './Draggable.js';

function App() {
  return (
    <React.Fragment>
        <Draggable />
    </React.Fragment>
  );
}

export default App;

Draggable.js

import React from 'react';

export class Draggable extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            pos: {x: 0, y: 0},
            dragging: false,
            rel: null
        };

        this.onMouseMove = this.onMouseMove.bind(this);
        this.onMouseDown = this.onMouseDown.bind(this);
        this.onMouseUp = this.onMouseUp.bind(this);
    }


    // we could get away with not having this (and just having the listeners on
    // our div), but then the experience would be possibly be janky. If there's
    // anything w/ a higher z-index that gets in the way, then you're toast,
    // etc.
    // componentDidUpdate(props, state) {
    //   if (this.state.dragging && !state.dragging) {
    //     document.addEventListener('mousemove', this.onMouseMove)
    //     document.addEventListener('mouseup', this.onMouseUp)
    //   } else if (!this.state.dragging && state.dragging) {
    //     document.removeEventListener('mousemove', this.onMouseMove)
    //     document.removeEventListener('mouseup', this.onMouseUp)
    //   }
    // }
  
    // calculate relative position to the mouse and set dragging=true
    onMouseDown(e) {
      console.log("1")
      console.log(this.state);
      if (e.button !== 0) return
      this.setState({
        dragging: true,
        rel: {
          x: e.pageX - e.nativeEvent.offsetX,
          y: e.pageY - e.nativeEvent.offsetY
        }
      })
      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: "absolute", left: "175px", top: "65px", border: "2px solid rgb(170, 170, 85)", padding: "10px"}}
            className="my-draggable" data-reactid=".r[2zxee]" id="messi" 
            onMouseDown={this.onMouseDown}
            onMouseUp={this.onMouseUp}
            onMouseDown={this.onMouseDown}
            initialPos = {{x:0,y:0}}
            >
                Drag Me! See how children are passed through to the div!
            </div>
        )
    }
}


export default Draggable;

在此代码中一切运行良好,显示了框,但我无法拖动 div,我无法弄清楚这是什么问题。我该如何解决这个问题?

这是我在 jsfiddle 中的示例代码

https://jsfiddle.net/6vdurk79/3/

将其转换为 React.Component:

时我注意到了一些事情
  1. 你在渲染时从未使用过this.state.pos,所以即使变量中的位置发生变化,它也不会移动div。 <div>style 属性只是 hard-coded 和 { left: "175px", top: "65px" }
  2. 您在 this.onMouseDown 函数中没有正确获取鼠标的位置,这导致它强制每个移动都在角落。
  3. 您从未将 this.onMouseMove 绑定到任何东西。取消注释掉大量注释掉的代码可以解决这个问题。
  4. 您放置在 <div> 中的 initialPos 属性完全没有任何作用。我在构造函数中将其转换为道具。

这是更新后的 JSFiddle link:https://jsfiddle.net/ogy4xd1c/3/

我将把它嵌入 Whosebug 的一个片段中。

class Draggable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pos: props.initialPos || {
        x: 0,
        y: 0
      },
      dragging: false,
      rel: null
    }

    this.onMouseMove = this.onMouseMove.bind(this);
    this.onMouseDown = this.onMouseDown.bind(this);
    this.onMouseUp = this.onMouseUp.bind(this);
  }

  // calculate relative position to the mouse and set dragging=true
  onMouseDown(e) {
    if (e.button !== 0) return
    const de = document.documentElement;
    const box = ReactDOM.findDOMNode(this).getBoundingClientRect();
    const top = box.top + window.pageYOffset - de.clientTop;
    const left = box.left + window.pageXOffset - de.clientLeft;
    this.setState({
      dragging: true,
      rel: {
        x: e.pageX - left,
        y: e.pageY - top,
      }
    })
    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()
  }

  componentDidUpdate(props, state) {
    if (this.state.dragging && !state.dragging) {
      document.addEventListener('mousemove', this.onMouseMove)
      document.addEventListener('mouseup', this.onMouseUp)
    } else if (!this.state.dragging && state.dragging) {
      document.removeEventListener('mousemove', this.onMouseMove)
      document.removeEventListener('mouseup', this.onMouseUp)
    }
  }

  render() {
    return ( <div
      style={{
            position: "absolute",
            left: this.state.pos.x,
            top: this.state.pos.y,
            border: "2px solid rgb(170, 170, 85)",
            padding: "10px"
        }}
        className="my-draggable"
        data-reactid=".r[2zxee]"
        id="messi"
        onMouseDown={this.onMouseDown}
        className="my-draggable"
      >
        Drag Me! See how children are passed through to the div!
      </div>
    )
  }
}

ReactDOM.render(<Draggable initialPos={{ x: 50, y: 20 }} />, document.querySelector("#root"));
.my-draggable {
  cursor: pointer;
  width: 200px;
  height: 200px;
  background-color: #cca;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

如果你想传入 children,你也可以使用这个修改后的版本:https://jsfiddle.net/hceLjz90/

class Draggable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pos: props.initialPos || {
        x: 0,
        y: 0
      },
      dragging: false,
      rel: null
    }

    this.onMouseMove = this.onMouseMove.bind(this);
    this.onMouseDown = this.onMouseDown.bind(this);
    this.onMouseUp = this.onMouseUp.bind(this);
  }

  // calculate relative position to the mouse and set dragging=true
  onMouseDown(e) {
    if (e.button !== 0) return
    const de = document.documentElement;
    const box = ReactDOM.findDOMNode(this).getBoundingClientRect();
    const top = box.top + window.pageYOffset - de.clientTop;
    const left = box.left + window.pageXOffset - de.clientLeft;
    this.setState({
      dragging: true,
      rel: {
        x: e.pageX - left,
        y: e.pageY - top,
      }
    })
    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()
  }

  componentDidUpdate(props, state) {
    if (this.state.dragging && !state.dragging) {
      document.addEventListener('mousemove', this.onMouseMove)
      document.addEventListener('mouseup', this.onMouseUp)
    } else if (!this.state.dragging && state.dragging) {
      document.removeEventListener('mousemove', this.onMouseMove)
      document.removeEventListener('mouseup', this.onMouseUp)
    }
  }

  render() {
    return ( <div
      style={{
            position: "absolute",
            left: this.state.pos.x,
            top: this.state.pos.y,
            border: "2px solid rgb(170, 170, 85)",
            padding: "10px"
        }}
        className="my-draggable"
        data-reactid=".r[2zxee]"
        id="messi"
        onMouseDown={this.onMouseDown}
        className="my-draggable"
      >
        {this.props.children}
      </div>
    )
  }
}

ReactDOM.render(<Draggable initialPos={{ x: 50, y: 20 }}>
    <h1>This is a child element</h1>
    <p>This is also a child element</p>
</Draggable>, document.querySelector("#root"))
.my-draggable {
  cursor: pointer;
  width: 200px;
  height: 200px;
  background-color: #cca;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>