首先還是要明確幾個概念,這里通過修改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表示對象整體的實際寬度,包括滾動條和邊框,會隨對象顯示大小的變化而改變。
4. clientLeft,clientTop
clientLeft,clientTop表示對象邊框的寬度。
5. scrollLeft,scrollTop
scrollLeft,scrollTop表示對象的顯示(可見)的內容與該對象實際的內容的距離。
6. offsetLeft,offsetTop
offsetLeft,offsetTop表示對象邊框的外邊緣距離與已定位的父容器(offsetparent)的內邊距離(不包括元素的邊框和父容器的邊框)。
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
