我是React的新手,想通过练习来学习。我正在尝试实现一个可拖动组件,该组件可包装一个子元素并捕获鼠标事件,然后触发从props
传递过来的函数,从而依次更新状态(和相关的CSS)。
我的可拖动组件如下:
import React from "react";
import PropTypes from "prop-types";
export default class Draggable extends React.Component {
constructor(props) {
super(props);
this.mouseMove = this.mouseMove.bind(this);
this.mouseUp = this.mouseUp.bind(this);
this.beginDrag = this.beginDrag.bind(this);
this.state = {
isDragging: false,
lastX: 0,
lastY: 0
};
}
static propTypes = {
onDrag: PropTypes.func.isRequired,
children: PropTypes.element.isRequired
};
render() {
const child = React.Children.only(this.props.children);
const newChild = React.cloneElement(child, {
onMouseDown: this.beginDrag
});
return newChild;
}
componentDidMount() {
window.addEventListener("mousemove", this.mouseMove.bind(this));
window.addEventListener("mouseup", this.mouseUp.bind(this));
}
componentWillUnmount() {
window.removeEventListener("mousemove", this.mouseMove);
window.removeEventListener("mouseup", this.mouseUp);
}
mouseMove(e) {
if (this.state.isDragging) {
const deltas = {
x: e.clientX - this.state.lastX,
y: e.clientY - this.state.lastY
};
this.setState({
lastX: e.clientX,
lastY: e.clientY
});
this.props.onDrag(deltas);
}
};
mouseUp() {
if (this.state.isDragging) {
this.setState({
isDragging: false
});
}
};
beginDrag(e) {
this.setState({
isDragging: true,
lastX: e.clientX,
lastY: e.clientY
});
};
}
示例用法:
import React from "react";
import Draggable from "./Draggable";
export default class SomeComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
translateX: 0,
translateY: 0
};
}
render() {
const style = {
top: this.state.translateY,
left: this.state.translateX
};
return (
<Draggable onDrag={this.onDrag}>
<div className="someComponent">
<div className="dragContainer" style={style}>
<div className="block">
hello world
</div>
<div className="block">
hello world
</div>
<div className="block">
hello world
</div>
</div>
</div>
</Draggable>
);
}
onDrag = (deltas) => {
this.setState(state => ({
translateX: state.translateX + deltas.x,
translateY: state.translateY + deltas.y
}));
};
}
相关的SCSS:
.someComponent {
display: block;
width: 100%;
height: 100%;
position: relative;
.dragContainer {
position: absolute;
}
.block {
display: inline-block:
}
}
在我拖动容器的意义上,拖动确实起作用,.dragContainer
的内容将按预期进行翻译。
问题是,当我开始从任何子元素(例如.block
之一)中拖动时,拖动也起作用。我可以通过在e.target
中测试Draggable.beginDrag
来缓解这种情况,但是我不知道该如何进行测试。理想情况下,我将e.target
与props
中传递的子元素进行比较,但是由于它是虚拟DOM,所以我敢肯定它不会起作用。
我应该将e.target
与什么进行比较?我已经读过React.createRef
,但不确定在这种情况下如何使用它。
答案 0 :(得分:0)
e.target
应该允许访问被单击的DOM节点。为什么不将event.target.id
与您为每个块提供的ID进行比较?然后,您可以根据比较结果执行所需的操作。