vue拖拽功能
必備知識點:
先給不懂的童鞋補充下流程,文章要細讀方能拖動元素到你心里~
按下的時候,我們需要獲取
元素當前的 具有相對定位元素的左側距離
元素當前的具有相對定位元素的頂部距離
鼠標按下點的x軸距離(鼠標左側的距離)
鼠標按下點的y軸距離 (鼠標頂部的距離)
獲取到這些點,先存儲起來,后面的計算需要用到這些值
start(e){ // 如果touches存在就說明是移動端 // 否則為pc端直接獲取事件源對象 let touch = e.touches? e.touches[0] : e; this.position.x = touch.clientX; this.position.y = touch.clientY; this.dx = moveDiv.offsetLeft; this.dy = moveDiv.offsetTop; }
Step1.
讓元素跟着鼠標的移動不斷移動。既然鼠標的x軸和y軸可以獲取到,那我們就可以通過計算來讓元素實現移動。
移動的時候,我們需要獲取並設置
鼠標此時的當前的x軸和y軸的距離
鼠標點擊的x軸和y軸的距離(按下的時候定義過)
此時用移動的距離 - 點擊的起始位置就是移動的距離。
賦值給點擊元素的left和top即可。
補充:計算的方式很多種,這知識其中一種
move(e){ let touch = e.touches? e.touches[0] : e; this.nx = touch.clientX - this.position.x; this.ny = touch.clientY - this.position.y; this.xPum = this.dx+this.nx; this.yPum = this.dy+this.ny; moveDiv.style.left = this.xPum + "px"; moveDiv.style.top = this.yPum + "px"; },
Step2.
離開的時候,我們需要抬起和移動事件從棧中清除掉,並且在結束時對邊界做一個處理。不讓元素拖動到屏幕外面,否則的話,不小心拖出去了,拉都拉不回來。這就很尷尬了。
元素的寬度
父元素的寬度和高度
元素的左側距離 + 元素的寬度
元素的頂部距離 + 元素的高度
end(e){ let oWidth = moveDiv.offsetWidth; // Element Width let oWrapWidth = moveDiv.parentNode.offsetWidth; // Parent Element Width let oWrprapHeight = moveDiv.parentNode.offsetHeight; // Parent Element Height let sumWidth = moveDiv.offsetLeft + oWidth; // Element Left + Element Width let sumHeight = moveDiv.offsetTop + moveDiv.offsetHeight; // Element Top + Element Height // The Limit Deal if(moveDiv.offsetLeft < 0) { moveDiv.style.left = 0; } else if(sumWidth > oWrapWidth){ moveDiv.style.left = oWrapWidth - oWidth + 'px'; } else if(moveDiv.offsetTop < 0) { moveDiv.style.top = 0; } else if(sumHeight > oWrprapHeight) { moveDiv.style.top = oWrprapHeight - moveDiv.offsetHeight + 'px'; } document.onmousemove = null; document.onmouseup = null; }
組件源碼
考慮到復用性,pc和移動端。
<template>
<!--S 拖動組件 -->
<div class="drag" id="moveDiv"
@mousedown="start($event)" @touchstart="start($event)"
@mousemove="move($event)" @touchmove="move($event)"
@mouseup="end($event)" @touchend="end($event)">
<slot name="drag-cont"></slot>
</div><!--E 拖動組件 -->
</template>
<script>
export default {
data() {
return {
position: {x: 0,y: 0}, // 鼠標點擊的x軸和y軸的距離
nx: '', // 鼠標當前距離元素的左側距離
ny: '', // 鼠標當前距離元素的頂部距離
dx: '', // 元素距離左側的距離
dy: '', // 元素距離頂部的距離
xPum: '', // 元素移動的x軸距離
yPum: '', // 元素移動的y軸距離
}
},
methods: {
start(e){
// 如果touches存在就說明是移動端
// 否則為pc端直接獲取事件源對象
let touch = e.touches? e.touches[0] : e;
this.position.x = touch.clientX;
this.position.y = touch.clientY;
this.dx = moveDiv.offsetLeft;
this.dy = moveDiv.offsetTop;
},
move(e){
let touch = e.touches? e.touches[0] : e;
this.nx = touch.clientX - this.position.x;
this.ny = touch.clientY - this.position.y;
this.xPum = this.dx+this.nx;
this.yPum = this.dy+this.ny;
moveDiv.style.left = this.xPum + "px";
moveDiv.style.top = this.yPum + "px";
document.addEventListener("touchmove",function(){
event.preventDefault();
},false);
if(e.preventDefault){
e.preventDefault();
}else{
window.event.returnValue == false;
}
},
end(e){
let oWidth = moveDiv.offsetWidth; // Element Width
let oWrapWidth = moveDiv.parentNode.offsetWidth; // Parent Element Width
let oWrprapHeight = moveDiv.parentNode.offsetHeight; // Parent Element Height
let sumWidth = moveDiv.offsetLeft + oWidth; // Element Left + Element Width
let sumHeight = moveDiv.offsetTop + moveDiv.offsetHeight; // Element Top + Element Height
// The Limit Deal
if(moveDiv.offsetLeft < 0) {
moveDiv.style.left = 0;
} else if(sumWidth > oWrapWidth){
moveDiv.style.left = oWrapWidth - oWidth + 'px';
} else if(moveDiv.offsetTop < 0) {
moveDiv.style.top = 0;
} else if(sumHeight > oWrprapHeight) {
moveDiv.style.top = oWrprapHeight - moveDiv.offsetHeight + 'px';
}
document.onmousemove = null;
document.onmouseup = null;
}
}
}
</script>
<style lang="less" scoped>
.drag {
position: absolute;
left: 0;
right: 0;
z-index: 999;
}
</style>
引入Demo
<Drag class="drag">
<div slot="drag-cont">訂單記錄</div>
</Drag>
<style>
.drag {
width: .6rem;
height: .6rem;
background-color: rgba(0, 0, 0,.55);
text-align: center;
line-height: .6rem;
font-size: .14rem;
color: #ffffff;
}
</style>
