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 { .6rem; height: .6rem; background-color: rgba(0, 0, 0,.55); text-align: center; line-height: .6rem; font-size: .14rem; color: #ffffff; } </style>