我有一个使包裹元素可拖动的组件。开始拖动时,我将事件侦听器添加到窗口中以进行拖动移动和放置。
>>> torch.Size([100, 80, 4, 4])
>>> torch.Size([100, 40, 9, 9])
>>> torch.Size([100, 40, 7, 7])
>>> RuntimeError: expected padding to be a single integer value or a list of 2 values to match the convolution dimensions, but got padding=[0, 1, 0, 1]
使用这些回调:
function start_drag({ x, y }) {
window.addEventListener('mouseup', trigger_drop);
window.addEventListener('mousemove', drag_move);
dispatch({ type: DispatchActions.START, x: x, y: y });
}
但是,这些回调使用自己的状态和调度版本。尝试了几件事之后,我无法解决此问题,此外,我对“ this”在此处的工作方式感到困惑。
我在React中工作,仅使用带有React Hooks的功能组件来获取状态等等。
对于许多其他stackoverflow问题,答案是使用绑定/箭头功能。如您所见,我将回调声明为箭头函数(不起作用),但是这使我感到有些奇怪。当我尝试绑定时,我发现我的功能组件中有 const trigger_drop = (e) => {
//if (!dragging) { return; }
end_drag();
if (deliver()) {
if (props.onDrop) {
props.onDrop(e);
}
}
}
const drag_move = (e) => {
//if (!state.dragging) { return; }
dispatch({ type: DispatchActions.MOVE, x: e.x, y: e.y });
if (props.onDragMove) {
props.onDragMove(e);
}
}
。这可能是相关的。我对此的搜索仅给出了答案,要求将其绑定到React.Component类的构造函数中,在这里不起作用。
这是该模块的完整代码:
this === undefined
预期:在window.mouseup上,我希望回调trigger_drop访问正确的import React, { useContext, useEffect, useReducer } from 'react';
import { DragContext } from 'client/contexts/DragContext';
import dragtarget from './DragTarget.module.css';
const DispatchActions = {
MOVE: 'move',
START: 'start',
STOP: 'stop'
}
function reducer(state, action) {
switch(action.type) {
case DispatchActions.MOVE:
return { ...state, offset_x: action.x - (state.start_x + state.offset_x), offset_y: action.y - (state.start_y + state.offset_y) };
case DispatchActions.START:
return { ...state, dragging: true, start_x: action.x, start_y: action.y, offset_x: 0, offset_y: 0 };
case DispatchActions.STOP:
return { ...state, dragging: false };
default:
return state;
}
}
export default function DragTarget(props) {
const { drag, deliver } = useContext(DragContext);
const [state, dispatch] = useReducer(reducer, {
dragging: false,
start_x: 0, start_y: 0,
offset_x: 0, offset_y: 0
});
useEffect(() => {
return () => {
end_drag();
};
}, []);
function start_drag({ x, y }) {
window.addEventListener('mouseup', trigger_drop);
window.addEventListener('mousemove', drag_move);
dispatch({ type: DispatchActions.START, x: x, y: y });
}
function end_drag() {
window.removeEventListener('mouseup', trigger_drop);
window.removeEventListener('mousemove', drag_move);
dispatch({ type: DispatchActions.STOP });
}
const trigger_drag = (e) => {
e.stopPropagation();
e.preventDefault();
if (drag(props.payload)) {
start_drag({ x: e.x, y: e.y });
if (props.onDragStart) {
props.onDragStart();
}
}
}
const drag_move = (e) => {
//if (!state.dragging) { return; }
dispatch({ type: DispatchActions.MOVE, x: e.x, y: e.y });
if (props.onDragMove) {
props.onDragMove(e);
}
}
const trigger_drop = (e) => {
//if (!state.dragging) { return; }
end_drag();
if (deliver()) {
if (props.onDrop) {
props.onDrop(e);
}
}
}
return (
<div className={`${props.className} ${state.dragging ? dragtarget.dragging : null}`} style={{ transform: `translate(${state.offset_x}px, ${state.offset_y}px)` }} onMouseDown={trigger_drag}>
{props.children}
</div>
);
}
和state.dragging
。与window.mousemove上的drag_move相同。
当前:在window.mouseup上,回调trigger_drop的状态副本。拖动将返回dispatch
(而不是引用具有false
的正确副本),并且drag_move调度到具有未定义元素的状态(状态=== true
)。
我希望我能清楚地解释这一点,否则请告诉我。预先感谢您的帮助!
答案 0 :(得分:1)
一种更简单的方法是摆脱调度异步操作,而利用可重用的组件将其自身状态作为单个对象处理,并进行同步setState
回调更新。
例如,您可以使用两个事件侦听器和一个事件回调来简化逻辑:一个用于mouseup
的事件监听器(单击鼠标)以保存元素,另一个用于mousemove
的事件监听器(当按住鼠标单击并移动鼠标)来转换元素,最后,您可以使用元素的onMouseDown
(鼠标单击释放)事件回调在其当前位置释放自己。
工作示例(此示例将styled-components
用于更干净的代码,但您不必这样做):
components / DragContainer / index.js
import styled from "styled-components";
export default styled.div.attrs(({ height, width, x, y }) => ({
style: {
transform: `translate(${x - width / 2}px, ${y - height / 2}px)`
}
}))`
cursor: grab;
position: absolute;
padding: 10px;
border-radius: 4px;
background-color: red;
${({ isDragging }) =>
isDragging &&
`
opacity: 0.5;
cursor: grabbing;
z-index: 999999;
`}
`;
components / Draggable / index.js
import React, {
useState,
useRef,
useEffect,
useCallback,
useLayoutEffect
} from "react";
import PropTypes from "prop-types";
import DragContainer from "../DragContainer";
const Draggable = ({ children, position }) => {
const dragRef = useRef(null);
const [state, setState] = useState({
isDragging: false,
translateX: position.x,
translateY: position.y,
height: 0,
width: 0
});
// mouse move
const handleMouseMove = useCallback(
({ clientX, clientY }) => {
if (state.isDragging) {
setState(prevState => ({
...prevState,
translateX: clientX,
translateY: clientY
}));
}
},
[state.isDragging]
);
// mouse left click release
const handleMouseUp = useCallback(() => {
if (state.isDragging) {
setState(prevState => ({
...prevState,
isDragging: false
}));
}
}, [state.isDragging]);
// mouse left click hold
const handleMouseDown = useCallback(() => {
setState(prevState => ({
...prevState,
isDragging: true
}));
}, []);
// before painting, get element height and width
// and zero out its position (this is
// necessary to force the cursor to point at the
// center of the element when dragging it)
useLayoutEffect(() => {
if (state.height < 1 && state.width < 1) {
const { offsetHeight, offsetWidth } = dragRef.current;
setState(prevState => ({
...prevState,
translateX: position.x + offsetWidth / 2,
translateY: position.y + offsetHeight / 2,
height: offsetHeight,
width: offsetWidth
}));
}
}, [position, state, setState, dragRef]);
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
};
}, [handleMouseMove, handleMouseUp]);
return (
<DragContainer
ref={dragRef}
isDragging={state.isDragging}
onMouseDown={handleMouseDown}
x={state.translateX}
y={state.translateY}
height={state.height}
width={state.width}
>
{children}
</DragContainer>
);
};
Draggable.propTypes = {
children: PropTypes.node.isRequired,
position: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number
})
};
Draggable.defaultProps = {
position: {
x: 10,
y: 10
}
};
export default Draggable;
index.js
import React, { Fragment } from "react";
import { render } from "react-dom";
import { Draggable, Title } from "./components";
const App = () => (
<Fragment>
<Draggable position={{ x: 20, y: 20 }}>
<Title>Hello</Title>
</Draggable>
<Draggable position={{ x: 140, y: 20 }}>
<Title>Goodbye</Title>
</Draggable>
</Fragment>
);
render(<App />, document.getElementById("root"));
答案 1 :(得分:0)
我认为您可以尝试e => trigger_drop(e, props, dispatch)
来获取正确的值和调度功能。