1. 程式人生 > >使用TypeScript給Vue 3.0寫一個指令實現元件拖拽

使用TypeScript給Vue 3.0寫一個指令實現元件拖拽

最近在用vue3重構後臺的一個功能。一個彈窗元件,彈出一個表單。然後點選提交。 早上運維突然跑過來問我,為啥彈窗擋住了下邊的表格的資料,我新增的時候,都沒法對照表格來看了。你必須給我解決一下。 我參考了一下幾大Vue的ui元件庫。發現element iview antv。好像都沒這個功能。為啥運維需要這個功能?? 但是沒辦法,只能整一個就是了。 做之前本來想直接做到dialog這個元件中。但是又擔心後面其他的元件會用到。於是決定把拖拽功能做到指令中。 ![](https://img2020.cnblogs.com/blog/653862/202010/653862-20201027095453079-1021273131.png) 整個功能點如圖。滑鼠在拖拽區域拖動,整個對話方塊在瀏覽器可視範圍內移動。 # Drag指令主要實現思路 1. 在指令掛載的時候,監聽當前html節點的滑鼠點選事件 2. 然後在點選當前html節點的時候,判斷是否點選在drag-target這個class所在的子節點上。如果是,那麼觸發document滑鼠移動事件。然後計算出滑鼠移動距離,對應修改彈出框的left值和top值。並記錄下當前按下的位置x和y ```javascript let x = e.clientX; let y = e.clientY; ``` 3. 如何限制拖動的節點只能在螢幕內移動,不能移動出螢幕呢? 1. 限制left不能小於0,在定位為**position: fixed** 的時候,left如果小於0,那麼html節點的左側肯定已經在顯示區域外了。那麼我們不能讓left小於0 ```javascript let bodyW = document.body.clientWidth; let bodyH = document.body.clientHeight; let left = elLeft - (x - move.clientX); if (left < 0) { left = 0; } ``` 2. 限制left不能大於可視區域的寬度減去當前html節點的寬度,如果left大於這個寬度,那麼當前html節點肯定右側已經處於顯示區域的右側外邊了 ``` javascript if (left > bodyW - el.offsetWidth) { left = bodyW - el.offsetWidth; } ``` 3. 上下拖拽位置限制和左右拖拽限制思路是一樣,只要保證top的值大於0且小於螢幕可視範圍的高度減去當前html節點的高度,那麼拖動就無法拖出螢幕了。 ``` javascript let top = elTop - (y - move.clientY); if (top < 0) { top = 0; } if (top > bodyH - el.offsetHeight) { top = bodyH - el.offsetHeight } ``` # drag指令完整程式碼 ```javascript import { App } from 'vue'; export default { install(Vue: App) { Vue.directive('drag', { mounted(el: HTMLElement, bind) { el.onmousedown = (e) => { let elLeft = el.offsetLeft; let elTop = el.offsetTop; let dom = e.target; if (dom.classList.contains('drag-target')) { let x = e.clientX; let y = e.clientY; document.onmousemove = (move: MouseEvent) => { let bodyW = document.body.clientWidth; let bodyH = document.body.clientHeight; let left = elLeft - (x - move.clientX); if (left < 0) { left = 0; } if (left > bodyW - el.offsetWidth) { left = bodyW - el.offsetWidth; } el.style.left = left + 'px' let top = elTop - (y - move.clientY); if (top < 0) { top = 0; } if (top > bodyH - el.offsetHeight) { top = bodyH - el.offsetHeight } el.style.top = top + 'px' document.onmouseup = (up: MouseEvent) => { document.onmousemove = null; document.onmouseup = null } if (window.getSelection()) { window.getSelection()?.removeAllRanges() } } } } }, unmounted(el, bind) { el.onmousedown = null; } }) } } ``` # 使用 ```javascript import DragDirective from './DragDirective' createApp(App).use(DragDirective).mount('#app') ``` 註冊指令到Vue App上,然後在需要移動的html節點上加上 **v-drag** ,並在觸發拖拽的子節點的class上,加上**drag-target** ``` html {{ title }}
``` # 效果圖 ![](https://img2020.cnblogs.com/blog/653862/202010/653862-20201027110732435-562225036.gif)
更多幹貨,以及本文的示例程式碼, 歡迎關注我的公眾號: 青城同學 回覆 拖拽程式碼 獲取下載地址 當然也可以掃碼 ![](https://img2020.cnblogs.com/blog/653862/202010/653862-20201024210609552-1491220