前言
被推拽元素,与其父元素,须放弃子绝父相,或子绝父绝。
案例
<!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0 , maximum-scale=1, minimum-scale=1, user-scalable=no" /> <title>Vue 自定义指令:拖拽</title> <link rel="shortcut icon" href="https://gw.alipayobjects.com/mdn/prod_resou/afts/img/A*CUIoT4xopNYAAAAAAAAAAABkARQnAQ" type="image/x-icon" /> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script> <style> * { margin: 0; padding: 0; overflow: hidden; box-sizing: border-box; } #app { width: 100vw; height: 100vh; overflow: hidden; } .box { display: flex; justify-content: center; align-items: center; position: absolute; width: 100px; height: 100px; border-radius: 10px; color: #fff; background-color: cadetblue; font-size: 60px; font-weight: bold; } </style> </head> <body> <div id="app"> <div class="box" v-drag>1</div> <div class="box" v-drag>2</div> <div class="box" v-drag>3</div> <div class="box" v-drag>4</div> <div class="box" v-drag>5</div> <div class="box" v-drag>6</div> <div class="box" v-drag>7</div> <div class="box" v-drag>8</div> <div class="box" v-drag>9</div> </div> <script> // 设置为 false 以阻止 Vue 在启动时生成生产提醒 Vue.config.productionTip = false // new 一个 Vue 实例,并挂载到 #app 上 new Vue({ el: '#app', data() { return {} }, directives: { // 对象写法,利用 inserted 钩子确保元素曾经被插入 DOM 时才执行 drag: { inserted(el) { el.onmousedown = (event) => { const parentEl = el.parentElement // 避免选中拖拽导致登程浏览器的搜寻事件 event.preventDefault() // 获取鼠标与拖拽盒子的偏移量(确保鼠标始终在点击盒子时的地位) const boxX = event.clientX - el.offsetLeft const boxY = event.clientY - el.offsetTop // 计算极限偏移量 const maxX = parentEl.offsetWidth - el.offsetWidth const maxY = parentEl.offsetHeight - el.offsetHeight // 获取拖拽元素的初始定位层级 const el_style = window.getComputedStyle(el, null) const origin_zIndex = el_style.zIndex const origin_cursor = el_style.cursor el.style.zIndex = '9999' el.style.cursor = 'move' document.onmousemove = (event) => { // 获取鼠标以后的地位 const mouseX = event.clientX const mouseY = event.clientY // 计算被拖拽盒子的偏移量 let moveX = mouseX - boxX let moveY = mouseY - boxY // 限度盒子的推拽范畴 moveX < 0 && (moveX = 0) moveY < 0 && (moveY = 0) moveX > maxX && (moveX = maxX) moveY > maxY && (moveY = maxY) // 赋予待拖拽的盒子新地位 el.style.left = moveX + 'px' el.style.top = moveY + 'px' } document.onmouseup = (event) => { // 还原初始层级 && 鼠标款式 el.style.zIndex = origin_zIndex el.style.cursor = origin_cursor document.onmousemove = null document.onmouseup = null } } }, }, }, }) </script> </body></html>