【练习小demo】使用React+TS实现一个拖动换位置效果(同时应用节流)

本练习demo旨在练习ts的使用,同时熟悉drag相关的事件

1.思路分析

mouse拖拽事件,通常有三个非常重要的过程:onMouseDown(鼠标按下) onMouseMove(鼠标拖动) onMouseUp(鼠标松开),通常我们在使用mouse拖拽这一事件的过程中,大概就是在这三个事件中进行相应的处理 我们最终要实现的demo效果,就是在鼠标按下后能够带动方块随鼠标位置移动,松开后固定在最后的位置。 如图: 移动后: 而这,只需要控制相关的定位:left和top就能实现这个功能(注意,left和top使用前,其position必须被规定为非static(默认) 在这里我们采用最简单的fixed布局就好(当然其他的也可以)

2.与react结合

我们采用react+ts来编写这个demo 创建命令:

1
npx create-react-app my-drag-demo --typescript

创建后直接改动app.tsx

3.节流函数的编写

节流函数的关键在于设置一个闸门,为了避免全局污染,我们用闭包来返回一个由节流函数包装后的函数 手写节流函数这种操作就不再这里赘述了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const throttle: (func: Function, interval: number) => Function = (
func: Function,
interval: number
) => {
let timer: any = null;
return (...arg: any) => {
if (!timer) {
timer = setTimeout(() => {
func(...arg);
timer = null;
}, interval);
}
};
};

4.业务逻辑编写

首先对于鼠标的点击,我们需要使用一个boolean变量来进行判断是否处在点击状态,然后用left变量和top变量来记录当前的位置,所以我们可以这样使用

1
2
3
const [left, setLeft] = useState(0);
const [top, setTop] = useState(0);
const [click, setClick] = useState(false);

定义好之后就可以进行相关逻辑的编写,其中要对onmousemove的逻辑进行节流函数包裹:

1
2
3
4
5
6
7
8
9
// 移动的事件触发函数
const drag: (event: Object) => void = (event: any) => {
if (click) {
setLeft(event.clientX - 200);
setTop(event.clientY - 200);
}
};
// 用节流函数包裹后:节流版本
const throttleDrag = throttle(drag, 10);

而其他逻辑和样式设置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div
style={{
position: "fixed",
left: left + "px",
top: top + "px",
backgroundColor: "#000000",
width: "400px",
height: "400px",
}}
onMouseDown={(event: any) => {
setClick(true);
setLeft(event.clientX - 200);
setTop(event.clientY - 200);
}}
onMouseMove={(event) => {
throttleDrag(event);
}}
onMouseUp={() => {
setClick(false);
}}
></div>

大功告成!

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { useRef, useState, useEffect } from "react";
const debounce: (func: Function) => Function = (func: Function) => {
let timer: any = null;
return (event: Object) => {
if (!timer) {
timer = setTimeout(() => {
func(event);
timer = null;
}, 10);
}
};
};
let click = false;
function App() {
let dragTest = useRef(null);
const [left, setLeft] = useState(0);
const [top, setTop] = useState(0);
useEffect(() => {}, [left, top]);
// 节流
const drag: (event: Object) => void = (event: any) => {
if (click) {
setLeft(event.clientX - 200);
setTop(event.clientY - 200);
}
};
const debouceDrag = debounce(drag);
return (
<div className="App">
<div
style={{
position: "fixed",
left: left + "px",
top: top + "px",
backgroundColor: "#000000",
width: "400px",
height: "400px",
}}
ref={dragTest}
onMouseDown={(event: any) => {
click = true;
setLeft(event.clientX - 200);
setTop(event.clientY - 200);
}}
onMouseMove={(event) => {
debouceDrag(event);
}}
onMouseUp={() => {
click = false;
}}
></div>
</div>
);
}

export default App;