- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个组件可以使包裹的元素可拖动。当我开始拖动时,我将事件监听器添加到窗口以进行拖放。
function start_drag({ x, y }) {
window.addEventListener('mouseup', trigger_drop);
window.addEventListener('mousemove', drag_move);
dispatch({ type: DispatchActions.START, x: x, y: y });
}
通过这些回调:
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);
}
}
但是,这些回调使用它们自己的状态和调度版本。在尝试了一些方法后,我无法解决这个问题,此外,我对“this”在这里的运作方式感到困惑。
我在 React 工作,只使用带有 React Hooks 的功能组件来处理状态等。许多其他 stackoverflow 问题的答案是使用绑定(bind)/箭头函数。如您所见,我将我的回调声明为箭头函数(不起作用),但这让我遇到了一些奇怪的事情;当我尝试绑定(bind)时,我发现我的功能组件中有 this === undefined
。这大概是有关系的。我对此的搜索只得出答案说要在 React.Component 类的构造函数中绑定(bind)它,这在这里不起作用。
这里是模块的完整代码:
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>
);
}
预期:在 window.mouseup 上,我希望回调 trigger_drop 访问正确的 state.dragging
和 dispatch
。与 window.mousemove 上的 drag_move 相同。
当前:在 window.mouseup 上,回调 trigger_drop 的 state.dragging 副本返回 false
(而不是引用正确的 true
),并且 drag_move 正在调度到其中包含未定义元素的状态(state === {dragging: true, start_x: undefined, start_y: undefined, offset_x: NaN, offset_y: NaN}
)。
我希望我解释清楚了,如果没有请告诉我。提前感谢您的帮助!
最佳答案
一种更简单的方法是放弃分派(dispatch)异步操作,而是利用可重用组件将其自身状态作为具有同步 setState
回调更新的单个对象来处理。
例如,您可以使用两个事件监听器和一个事件回调来简化您的逻辑:一个事件监听器用于 mouseup
(鼠标单击)以保持元素,另一个事件监听器用于 mousemove
(按住鼠标单击并移动鼠标时)平移元素,最后您可以使用元素的 onMouseDown
(鼠标单击释放)事件回调在其当前位置释放自身。
工作示例(此示例使用 styled-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"));
关于javascript - 为什么我的事件监听器回调没有使用正确的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57422136/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!