SockSTap S O C K S T A P

Vue使用自定义指令实现拖拽行为

首页 / 新闻资讯 / 正文

需求

通过自定义指令的方式实现拖拽效果,预期的使用方式为:

        <div style="background: #f00; width: 200px; height: 200px;" v-drag>             XXXX         </div> 

更重要的一个需求点:

  • 拖拽元素内部的子元素可以自行阻止拖拽行为

比如:

   <div style="background: #f00; width: 200px; height: 200px;" v-drag>       <el-button @mousedown.native.stop>test</el-button> </div> 

曾经使用过vue-resizable,由于该组件是通过事件捕获的方式实现的,拖拽元素的子元素也会触发拖拽行为,不符合开发需求,所以自行实现了拖拽指令,相关源码如下。

无任何依赖,复制即可使用

源码

/**  * @file 自定义拖拽命令  */  import Vue from 'vue';  const Drag = {     install(Vue: any) {         // 如需禁止拖拽元素内部某些元素触发拖拽,在内部不可触发拖拽元素上添加@mousedown.native.stop即可         Vue.directive('drag', {             bind(el: any) {                 el.style.position = 'absolute';                 el.style.zIndex = el.style.zIndex || '3000';             },              inserted(el: any) {                 // 设置元素初始位置                 const boundingClientRect = el.getBoundingClientRect();                 el.style.left = boundingClientRect.x + 'px';                 el.style.top = boundingClientRect.y + 'px';                 // 将拖拽元素置于body子元素,防止被relative的父元素遮挡                 document.body.appendChild(el);                  let originX: number;                 let originY: number;                 const mouseDownHandler = (evt: MouseEvent) => {                     originX = evt.clientX - el.offsetLeft;                     originY = evt.clientY - el.offsetTop;                     el.style.cursor = 'pointer';                 };                 const mouseMoveHandler = (evt: MouseEvent) => {                     if (evt.buttons === 1 && originX && originY) {                         el.style.left = evt.clientX - originX + 'px';                         el.style.top = evt.clientY - originY + 'px';                     }                 };                 const mouseUpHandler = () => {                     el.style.cursor = 'default';                 };                 el.addEventListener('mousedown', mouseDownHandler);                 el.addEventListener('mousemove', mouseMoveHandler);                 el.addEventListener('mouseup', mouseUpHandler);                 el.__mouseDownHandler__ = mouseDownHandler;                 el.__mouseMoveHandler__ = mouseMoveHandler;                 el.__mouseUpHandler__ = mouseUpHandler;             },              unbind(el: any) {                 el.removeEventListener('mousedown', el.__mouseDownHandler__);                 el.removeEventListener('mousemove', el.__mouseMoveHandler__);                 el.removeEventListener('mouseup', el.__mouseUpHandler__);                 // 当父组件销毁触发unbind的时候需要手动删除这个节点,不然会一直存留在body中                 el.parentNode.removeChild(el);             }         });     } }; Vue.use(Drag); export default Drag;