簡單實現el-dialog的拖拽功能


首先還是要明確幾個概念,這里通過修改css並截圖給大家介紹下,理解了這幾個概念,代碼寫起來會得心應手許多。

  • clientWidth,clientHeight
  • scrollWidth,scrollHeight
  • offsetWidth,offsetHeight
  • clientLeft,clientTop
  • scrollLeft,scrollTop
  • offsetLeft,offsetTop

1. clientWidth,clientHeight

clientWidth,clientHeight表示對象內容的可視區的寬度,不包括滾動條和邊框,會隨對象顯示大小的變化而改變。


上圖中,我給el-scrollbar__view這個div增加了10px的紅色邊框,整個div的實際高度,寬度變成了3452px,1920px,觀察clientWidth,clientHeight的值是3432px,1900px,並沒有包含邊框和滾動條的寬度。

2. scrollWidth,scrollHeight

scrollWidth,scrollHeight表示對象的實際內容的寬度,不包括邊框(但是包括滾動條),會隨對象中內容超過可視區后而變大。

 

上圖中,我還是給el-scrollbar__view這個div增加了10px的紅色邊框,整個div的實際高度,寬度變成了3452px,1920px,觀察scrollWidth,scrollHeight的值是3432px,1900px,並沒有包含邊框的寬度。

3. offsetWidth,offsetHeight

offsetWidth,offsetHeight表示對象整體的實際寬度,包括滾動條和邊框,會隨對象顯示大小的變化而改變。

 上圖中,我還是給el-scrollbar__view這個div增加了10px的紅色邊框,整個div的實際高度,寬度變成了3452px,1920px,觀察scrollWidth,scrollHeight的值仍然是3452px,1920px,包含滾動條和邊框。

4. clientLeft,clientTop

clientLeft,clientTop表示對象邊框的寬度。

 上圖中,我還是給el-scrollbar__view這個div增加了10px的紅色邊框,觀察clientLeft, clientTop均為10px。

5. scrollLeft,scrollTop

scrollLeft,scrollTop表示對象的顯示(可見)的內容與該對象實際的內容的距離。

 上圖中,我們給content這個section設置了寬高均是300px,並設置顯示滾動條,將滾動條拖動一部分,觀察scrollLeft,scrollTop的值分別是164px,204px,這對應着當前內容距離原來實際內容的距離(假設藍色框是實際內容的距離)。

6. offsetLeft,offsetTop

offsetLeft,offsetTop表示對象邊框的外邊緣距離與已定位的父容器(offsetparent)的內邊距離(不包括元素的邊框和父容器的邊框)。

 
上圖中,el-dialog這個div距離已定位的父容器(這里是el-dialog__wrapper)的寬高分別是672px,61px,與offsetLeft,offsetTop值一致。
 
 
我們給el-dialog__wrapper加上一個20px的黃色邊框,給el-dialog加上一個10px的藍色邊框,再來觀察offsetLeft,offsetTop的值,發現在計算時,是從黃色邊框的內邊距到藍色邊框的外邊距,不包括邊框。

7. coding

明確上述概念之后,我們來着手寫代碼,先說下我的業務場景。
有一個dialog彈框,彈框的背景並不是全屏的,只在除header,sidebar的地方顯示,要求拖拽dialog彈框不能超過背景。
我們在main.js同級目錄創建directives.js,具體代碼如下

 1 import Vue from 'vue';
 2 
 3 // v-dialogDrag 彈窗拖拽
 4 Vue.directive('dialogDrag', {
 5     bind(el, binding, vnode, oldVnode) {
 6         const dialogHeaderEl = el.querySelector('.el-dialog__header');
 7         const dragDom = el.querySelector('.el-dialog');
 8         dialogHeaderEl.style.cursor = 'move';
 9         // 獲取原有屬性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
10         const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
11         dialogHeaderEl.onmousedown = (e) => {
12             console.log('屏幕高度', document.documentElement.clientHeight);
13             console.log('彈窗高度', dragDom.offsetHeight);
14             // 鼠標按下,獲取鼠標在盒子內的坐標
15             const disX = e.clientX - dialogHeaderEl.offsetLeft;
16             const disY = e.clientY - dialogHeaderEl.offsetTop;
17             // 獲取到的值帶px 正則匹配替換
18             let styL;
19             let styT;
20             // 注意在ie中 第一次獲取到的值為組件自帶50% 移動之后賦值為px
21             if (sty.left.includes('%')) {
22                 styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
23                 styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
24             } else {
25                 styL = +sty.left.replace(/\px/g, '');
26                 styT = +sty.top.replace(/\px/g, '');
27             }
28             // 鼠標移動的時候,把鼠標在頁面中的坐標,減去鼠標在盒子內的坐標就是模態框的left和top值
29             document.onmousemove = function(e) {
30                 // 通過事件委托,計算移動的距離 (開始拖拽至結束拖拽的距離)
31                 const l = e.clientX - disX;
32                 const t = e.clientY - disY;
33 
34                 let finallyL = l + styL;
35                 let finallyT = t + styT;
36 
37                 // 邊界值判定 注意clientWidth scrollWidth區別 要減去之前的top left值
38                 let limitL = (document.documentElement.clientWidth - dragDom.clientWidth) / 2;
39                 if (finallyL < -limitL) {
40                     finallyL = -limitL;
41                 } else if (finallyL > limitL) {
42                     finallyL = limitL;
43                 }
44                 let limitT = document.documentElement.clientHeight * 15 / 100;
45                 let limitB = document.documentElement.clientHeight - dragDom.clientHeight - limitT;
46                 if (finallyT < -limitT) {
47                     finallyT = -limitT;
48                 } else if (finallyT > limitB) {
49                     finallyT = limitB;
50                 }
51                 // 移動當前元素
52                 dragDom.style.left = `${finallyL}px`;
53                 dragDom.style.top = `${finallyT}px`;
54             };
55             document.onmouseup = function(e) {
56                 document.onmousemove = null;
57                 document.onmouseup = null;
58             };
59         };
60     }
61 });

參考網址:https://www.jianshu.com/p/c3ce06c423af?tdsourcetag=s_pctim_aiomsg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM