文章最后会有全部代码
看这里,了解vue提供的自定义指令包含的钩子函数。
- 当使用自定义指令时,钩子函数可以获取到当前指令所绑定的dom!
- 当在组件上使用自定义指令时,它会始终应用于组件的根节点!
元素可以拖动,也就是说元素的位置发生变化,发生变化的方式要么是利用定位改变元素的left、top属性,要么利用transform改变元素的偏移量。在此之上进行对鼠标事件的监听便可,用到的鼠标事件:
mousedown
事件,记录元素初始偏移位置;mousemove
事件,根据鼠标位移向量修改元素的偏移位置;mouseup
事件,重置数据。
创建拖拽指令
const drag ={
mounted(el, binding){
// el->当前dom元素
// binding-> 可选参数对象
}
}
添加鼠标监听
const onMouseDown = (e) => {
e.stopPropagation();
startPosition = getPosition(e);
if (outerElement && element) {
const outerElementRect = outerElement.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
draggingMoveVectorRange = [outerElementRect.top - elementRect.top, outerElementRect.bottom - elementRect.bottom, outerElementRect.left - elementRect.left, outerElementRect.right - elementRect.right];
}
};
const onMouseMove = (e) => {
if (startPosition && draggingMoveVectorRange) {
endPosition = getPosition(e);
const currentMoveVector = formatV(minusV(startPosition, endPosition), draggingMoveVectorRange);
draggingMoveVector = addV(draggedMoveVector, currentMoveVector);
element.style.transform = setTranslatePosition(startTransform, draggingMoveVector);
}
};
const onMouseUp = (e) => {
if (startPosition && draggingMoveVectorRange) {
draggedMoveVector = draggingMoveVector;
}
startPosition = null;
};
全部代码:
export const drag = {
mounted(el, binding) {
const addV = (v1, v2) => {
const x = v1[0] + v2[0];
const y = v1[1] + v2[1];
return [x, y];
};
const minusV = (v1, v2) => {
const x = v2[0] - v1[0];
const y = v2[1] - v1[1];
return [x, y];
};
const formatV = (v, range) => {
let x = v[0];
let y = v[1];
x = Math.max(x, range[2]);
x = Math.min(x, range[3]);
y = Math.max(y, range[0]);
y = Math.min(y, range[1]);
return [x, y];
};
const setTranslatePosition = (transform, v) => {
return `translate(${v[0]}px, ${v[1]}px)`;
};
const getPosition = (e) => {
if (e instanceof MouseEvent) {
return [e.pageX, e.pageY];
}
const touch = e.touches[0];
return [touch.pageX, touch.pageY];
};
const enableDrag = (element) => {
let { outerElement, innerElement } = {};
let startTransform = window.getComputedStyle(element).transform;
let startPosition = null;
let endPosition = null;
let draggingMoveVectorRange = null;
let draggedMoveVector = [0, 0];
let draggingMoveVector = [0, 0];
outerElement = document.body;
innerElement = element;
const onMouseDown = (e) => {
e.stopPropagation();
startPosition = getPosition(e);
if (outerElement && element) {
const outerElementRect = outerElement.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
draggingMoveVectorRange = [outerElementRect.top - elementRect.top, outerElementRect.bottom - elementRect.bottom, outerElementRect.left - elementRect.left, outerElementRect.right - elementRect.right];
}
};
const onMouseMove = (e) => {
if (startPosition && draggingMoveVectorRange) {
endPosition = getPosition(e);
const currentMoveVector = formatV(minusV(startPosition, endPosition), draggingMoveVectorRange);
draggingMoveVector = addV(draggedMoveVector, currentMoveVector);
element.style.transform = setTranslatePosition(startTransform, draggingMoveVector);
}
};
const onMouseUp = (e) => {
if (startPosition && draggingMoveVectorRange) {
draggedMoveVector = draggingMoveVector;
}
startPosition = null;
};
const addEventListener = () => {
if (innerElement) {
innerElement.addEventListener("mousedown", onMouseDown);
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
}
};
const removeEventListener = () => {
if (innerElement) {
innerElement.removeEventListener("mousedown", onMouseDown);
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
};
addEventListener();
return removeEventListener;
};
enableDrag(el);
},
unmounted(el, binding, vnode, prevVnode) {
// el.removeEventListener("mousedown", onMousedown);
},
};
注册为全局的指令后在需要的元素上声明v-drag 指令:
<div v-drag>
<span>这是一个可以被拖动的元素</span>
</div>