# dnd-拖拽改变文件的位置
# 1. 介绍
原理:
侦听元素的 mousedown 事件
一旦 mousedown,则注册 mousemove 和 mouseup,并记录元素初始的位置和鼠标按下的位置
- 在 mousemove 里改变元素的位置
- 在 mouseup 里注销 mousemove 和 mouseup 事件
缺点:
- 需要在模板元素上注册事件,如果光标移动过快,则元素不会随光标移动 且 事件不能注销,造成操作错乱
# 2. 快速开始
<style>
#box {
position: absolute;
top: 100px;
left: 200px;
width: 100px;
height: 100px;
background: red;
}
</style>
<div id="box"></div>
<script>
const boxElement = document.querySelector('#box');
let position = {
origin: { x: 0, y: 0 },
mousedown: { x: 0, y: 0 },
mousemove: { x: 0, y: 0 },
};
const update = () => {
const { origin: { x, y }, mousedown, mousemove } = position;
const deltaX = mousemove.x - mousedown.x;
const deltaY = mousemove.y - mousedown.y;
boxElement.style.left = `${x + deltaX}px`;
boxElement.style.top = `${y + deltaY}px`;
};
const mousemoveHandler = (event) => {
const { x, y } = event;
position.mousemove.x = x;
position.mousemove.y = y;
update();
};
const mouseupHandler = () => {
boxElement.removeEventListener('mousemove', mousemoveHandler, false);
boxElement.removeEventListener('mouseup', mouseupHandler, false);
};
const mousedownHandler = (event) => {
position.mousedown.x = event.x;
position.mousedown.y = event.y;
const { x, y } = boxElement.getBoundingClientRect();
position.origin.x = x;
position.origin.y = y;
boxElement.addEventListener('mousemove', mousemoveHandler, false);
boxElement.addEventListener('mouseup', mouseupHandler, false);
}
boxElement.addEventListener('mousedown', mousedownHandler, false);
</script>
# 3. 封装为类
class Draggable {
/** @type {HTMLElement} */
target = null;
/** @type {HTMLElement} */
handle = null;
/** @type {HTMLElement} */
container = null;
options = {
/**
* default target
* @type {HTMLElement | string}
*/
handle: null,
/**
* @type {HTMLElement | string}
*/
container: document.body,
};
/**
* @param target {HTMLElement | string}
* @param options {{ handle?: HTMLElement | string, container?: HTMLElement | string }}
*/
constructor(target, options = {}) {
this.setTarget(target);
this.setOptions(options);
this.setHandle();
this.setContainer();
this.setDraggable();
}
setTarget(target) {
this.target = this.getElement(target);
}
setOptions(options) {
this.options = {
...this.options,
...options,
};
}
setHandle() {
const { handle } = this.options;
if (!handle) {
this.handle = this.target;
return;
}
this.handle = this.getElement(handle);
}
setContainer() {
const { container } = this.options;
this.container = this.getElement(container);
}
getElement(selectorOrElement) {
if (typeof selectorOrElement === 'string') {
return document.querySelector(selectorOrElement);
}
return selectorOrElement;
}
setDraggable() {
this.handle.addEventListener('mousedown', this.handleMousedown);
}
/** @param event {MouseEvent} */
handleMousedown = (event) => {
this.container.addEventListener('mousemove', this.handleMousemove);
this.container.addEventListener('mouseup', this.handleMouseup);
event.preventDefault();
}
handleMouseup = () => {
this.container.removeEventListener('mousemove', this.handleMousemove);
this.container.removeEventListener('mouseup', this.handleMouseup);
}
/** @param event {MouseEvent} */
handleMousemove = (event) => {
const { movementX: offsetX, movementY: offsetY } = event;
const { x: left, y: top } = this.getTargetPosition();
this.setTargetPosition(left + offsetX, top + offsetY);
event.preventDefault();
}
setTargetPosition(x, y) {
this.target.style.left = `${x}px`;
this.target.style.top = `${y}px`;
}
getTargetPosition() {
const { x, y } = this.target.getBoundingClientRect();
return { x, y };
}
destroy() {
this.handle.removeEventListener('mousedown', this.handleMousedown);
this.target = null;
this.handle = null;
this.container = null;
this.options = null;
}
}
export default Draggable;
# 4. 参考
上一篇: 下一篇:
本章目录