你可能發現有不少網站他們的登陸窗口或者說是登陸框是能夠拖動的, 更有甚者他們的站點提示框均可以拖動, 你也許可能會對這個功能的實現感興趣, 那麼這篇文章可能會對你有所幫助!具體的網站示例以
網易雲音樂
Web站點爲例,具體效果以下圖所示:
預先假設要實現的登陸框容許點擊鼠標獲取拖拽事件的具體位置就是登陸框的標題區塊也就是下圖所示登陸區塊黑色部分在文章中以容許點擊鼠標獲取拖拽事件區域
說明問題, 而且假定紅色十字
圖標就是鼠標狀態:
容許點擊鼠標獲取拖拽事件區域
點擊鼠標時觸發 onmousedown
事件容許點擊鼠標獲取拖拽事件區域
點擊時的具體位置
當鼠標移動時改變 登陸窗口
左上角位置(也是就是座標點位置)距離頁面可視區左上角位置, 那麼這個 登陸窗口
也就移動了, 也就實現了 登陸窗口
的拖拽功能html
onmousemove
事件當鼠標擡起時, 觸發 onmouseup
事件git
onmousemove
事件onmouseup
事件自身
以上過程就是一個完整的
登陸窗口
拖拽的過程, 不過要注意如下幾點:
拖拽移動 登陸窗口
時爲 document
綁定 onmousemove
事件, 而不是 容許點擊鼠標獲取拖拽事件區域
github
容許點擊鼠標獲取拖拽事件區域
綁定 onmousemove
件事, 當鼠標移動的快了就會致使事件綁定丟失, 不過你能夠去驗證onmousemove
綁定到 容許點擊鼠標獲取拖拽事件區域
這樣其是不對的!onmousemove
綁定到 document
上的事件, 這樣纔是最完美的, 由於你無論怎麼拖它都不會丟失事件綁定擡起鼠標時一樣也是爲 document
綁定 onmouseup
事件, 而不是 容許點擊鼠標獲取拖拽事件區域
web
容許點擊鼠標獲取拖拽事件區域
綁定 onmouseup
事件, 你會發現當鼠標移動到脫離文檔可視區域時,擡起點擊的鼠標按鍵你會發現當再一次移動鼠標時它依然能夠移動這就不符合常理了不是嘛!那就給 document
綁定 onmouseup
事件時,它就能夠很好的解決這個怪異的問題!onmouseup
綁定到 容許點擊鼠標獲取拖拽事件區域
這樣其是不對的!onmouseup
綁定到 document
上的事件, 這樣纔是最完美的<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JS拖拽</title> <style> /* public style start */ * { margin: 0; padding: 0; } body, textarea, select, input, button {font-size: 12px;color: white;font-family: Arial, Helvetica, sans-serif;-webkit-text-size-adjust: none;} .fl-l { float: left } .fl-r { float: right } .clearfix:after {visibility:hidden;display:block;font-size:0;content:'.';clear:both;height:0;} .clearfix {*zoom:1;} /* public style end */ /* dialog window style start */ /* dialog window main */ #dialog { height: 200px; width: 400px; background-color: #EAF6DB; border: 1px solid lightslategray; position: absolute; top: 200px; left: 400px; } /* dialog window title section */ .dialog-title { height: 40px; line-height: 40px; background-color: #3a3333; cursor: move; } /* dialog window title inner detail */ .login, .close { display: inline-block; margin: 0 15px; } </style> <script> window.onload = function () { // 獲取DOM元素 var oDialog_title = document.getElementById( 'dialog-title' ); // 容許點擊鼠標獲取拖拽事件區域 var oDialog = oDialog_title.parentNode; // 登陸窗口 // 初始化鼠標默認位置 var iDisX = 0; var iDisY = 0; // 爲獲取到的DOM元素添加鼠標按下事件 `onmousedown` oDialog_title.onmousedown = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 距離計算鼠標位於彈出框內的位置 iDisX = oEvent.clientX - oDialog.offsetLeft; // 鼠標X軸位置 - 彈出框X外左邊距 iDisY = oEvent.clientY - oDialog.offsetTop; // 鼠標Y軸位置 - 彈出框Y外上邊距 // 點擊彈出框後拖動鼠標, 移動彈出框 document.onmousemove = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 當鼠標移動時改變彈出框的位置 oDialog.style.left = oEvent.clientX - iDisX + 'px'; oDialog.style.top = oEvent.clientY - iDisY + 'px'; }; // 當點擊鼠標拖動彈出框, 擡起鼠標時 document.onmouseup = function () { // 清除彈出框的移動事件及自己 document.onmousemove = null; document.onmouseup = null; }; // 阻止默認事件, 若是不加這個阻止默認事件, 在firefox下會有一個獲取焦點的光標一直在閃動, 在3.0及如下會出現拖動出現重影的狀況 return false; }; }; </script> </head> <body> <!-- 假設這個DIV就是一個登陸窗口 --> <div id="dialog"> <div id="dialog-title" class="dialog-title clearfix"> <span class="fl-l login">登陸</span> <span class="fl-r close">X</span> </div> </div> </body> </html>
以上就是以一個簡單的DIV模擬
登陸窗口
實現的一個簡單拖拽過程
你可能已經發現了這個登陸窗口
與網易雲音樂
最大的區別在於它能夠拖拽出文檔可視區域, 它甚至能夠拖拽到文檔不可見區域, 那就永遠拖不回了, 就像那已分手並結婚了的前女朋友永遠也回不來同樣
(好了, 找一沒人的地哭暈在廁所好了 是否是同時又想起來那幾句話[得不到的永遠在騷動, 失去的永遠在懷念, 身邊的永遠成爲風景, ......]), 以上是逗逼時刻就當沒發生同樣好了其實這也是上面留的一個坑, 如今來優化填坑, 就是實現和
網易雲音樂
網站登陸窗口
同樣的效果, 禁止登陸窗口
拖拽出文檔可視區之外! 下面是填坑時刻, 非戰鬥人員請火速離開現場 學習
其實思路很簡單就是當登陸窗口
的四個邊和文檔窗口的其一邊界重合時, 就讓登陸窗口
的那一個邊的外邊距值與重合的文檔那一個邊的值相等, 那這個事情就妥妥的搞定了!
documnet.onmousemove
事件方法 登陸窗口
當前位置便可!// 當鼠標移動時改變彈出框的位置 oDialog.style.left = oEvent.clientX - iDisX + 'px'; oDialog.style.top = oEvent.clientY - iDisY + 'px';
// 優化填坑 - 禁止 `登陸窗口` 拖拽出文檔可視區域, 保存 `登陸窗口` 在文檔中具體位置 var iCurrentDialogDisLift = oEvent.clientX - iDisX; // `登陸窗口` 當前位置於X軸具體值 var iCurrentDialogDisTop = oEvent.clientY - iDisY; // `登陸窗口` 當前位置於Y軸具體值 // 檢測當前 `登陸窗口` X軸是否位於文檔可視區域最左側或最右側 if ( iCurrentDialogDisLift < 0 ) { iCurrentDialogDisLift = 0; } else if ( iCurrentDialogDisLift > document.documentElement.clientWidth - oDialog.offsetWidth ) { // 當前文檔X軸可視區域大小包括左右邊框線寬度 - `登陸窗口` X軸區域大小包括左右邊框線寬度 iCurrentDialogDisLift = document.documentElement.clientWidth - oDialog.offsetWidth; } // 檢測當前 `登陸窗口` Y軸是否位於文檔可視區域最上端或最下端 if ( iCurrentDialogDisTop < 0 ) { iCurrentDialogDisTop = 0; } else if ( iCurrentDialogDisTop > document.documentElement.clientHeight - oDialog.offsetHeight ) { // 當前文檔Y軸可視區域大小包括上下邊框線寬度 - `登陸窗口` Y軸區域大小包括上下邊框線寬度 iCurrentDialogDisTop = document.documentElement.clientHeight - oDialog.offsetHeight; } // 當鼠標移動時改變彈出框的位置 oDialog.style.left = iCurrentDialogDisLift + 'px'; oDialog.style.top = iCurrentDialogDisTop + 'px';
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JS拖拽</title> <style> /* public style start */ * { margin: 0; padding: 0; } body, textarea, select, input, button {font-size: 12px;color: white;font-family: Arial, Helvetica, sans-serif;-webkit-text-size-adjust: none;} .fl-l { float: left } .fl-r { float: right } .clearfix:after {visibility:hidden;display:block;font-size:0;content:'.';clear:both;height:0;} .clearfix {*zoom:1;} /* public style end */ /* dialog window style start */ /* dialog window main */ #dialog { height: 200px; width: 400px; background-color: #EAF6DB; border: 1px solid lightslategray; position: absolute; top: 200px; left: 400px; } /* dialog window title section */ .dialog-title { height: 40px; line-height: 40px; background-color: #3a3333; cursor: move; } /* dialog window title inner detail */ .login, .close { display: inline-block; margin: 0 15px; } </style> <script> window.onload = function () { // 獲取DOM元素 var oDialog_title = document.getElementById( 'dialog-title' ); // 容許點擊鼠標獲取拖拽事件區域 var oDialog = oDialog_title.parentNode; // 登陸窗口 // 初始化鼠標默認位置 var iDisX = 0; var iDisY = 0; // 爲獲取到的DOM元素添加鼠標按下事件 `onmousedown` oDialog_title.onmousedown = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 距離計算鼠標位於彈出框內的位置 iDisX = oEvent.clientX - oDialog.offsetLeft; // 鼠標X軸位置 - 彈出框X外左邊距 iDisY = oEvent.clientY - oDialog.offsetTop; // 鼠標Y軸位置 - 彈出框Y外上邊距 // 點擊彈出框後拖動鼠標, 移動彈出框 document.onmousemove = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 優化填坑 - 禁止 `登陸窗口` 拖拽出文檔可視區域, 保存 `登陸窗口` 在文檔中具體位置 var iCurrentDialogDisLift = oEvent.clientX - iDisX; // `登陸窗口` 當前位置於X軸具體值 var iCurrentDialogDisTop = oEvent.clientY - iDisY; // `登陸窗口` 當前位置於Y軸具體值 // 檢測當前 `登陸窗口` X軸是否位於文檔可視區域最左側或最右側 if ( iCurrentDialogDisLift < 0 ) { iCurrentDialogDisLift = 0; } else if ( iCurrentDialogDisLift > document.documentElement.clientWidth - oDialog.offsetWidth ) { // 當前文檔X軸可視區域大小包括左右邊框線寬度 - `登陸窗口` X軸區域大小包括左右邊框線寬度 iCurrentDialogDisLift = document.documentElement.clientWidth - oDialog.offsetWidth; } // 檢測當前 `登陸窗口` Y軸是否位於文檔可視區域最上端或最下端 if ( iCurrentDialogDisTop < 0 ) { iCurrentDialogDisTop = 0; } else if ( iCurrentDialogDisTop > document.documentElement.clientHeight - oDialog.offsetHeight ) { // 當前文檔Y軸可視區域大小包括上下邊框線寬度 - `登陸窗口` Y軸區域大小包括上下邊框線寬度 iCurrentDialogDisTop = document.documentElement.clientHeight - oDialog.offsetHeight; } // 當鼠標移動時改變彈出框的位置 oDialog.style.left = iCurrentDialogDisLift + 'px'; oDialog.style.top = iCurrentDialogDisTop + 'px'; }; // 當點擊鼠標拖動彈出框, 擡起鼠標時 document.onmouseup = function () { // 清除彈出框的移動事件及自己 document.onmousemove = null; document.onmouseup = null; }; // 阻止默認事件, 若是不加這個阻止默認事件, 在firefox下會有一個獲取焦點的光標一直在閃動, 在3.0及如下會出現拖動出現重影的狀況 return false; }; }; </script> </head> <body> <!-- 假設這個DIV就是一個登陸窗口 --> <div id="dialog"> <div id="dialog-title" class="dialog-title clearfix"> <span class="fl-l login">登陸</span> <span class="fl-r close">X</span> </div> </div> </body> </html>
文章寫到這裏可能也有不夥伴說了, 滾動一小段距離也就是出現滾動條時, 再拖拽仍是會出現登陸窗口
脫離可視區域的狀況!對於小夥伴提出的問題至少有二種解決方案!優化
登陸窗口
位於正中間而且只容許在可視區域拖拽登陸窗口
時禁止滾動下面來一個一個的說:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JS拖拽擴展-計算滾動距離</title> <style> /* public style start */ * { margin: 0; padding: 0; } body, textarea, select, input, button {font-size: 12px;color: white;font-family: Arial, Helvetica, sans-serif;-webkit-text-size-adjust: none;} .fl-l { float: left } .fl-r { float: right } .clearfix:after {visibility:hidden;display:block;font-size:0;content:'.';clear:both;height:0;} .clearfix {*zoom:1;} /* public style end */ /* dialog window style start */ /* dialog window main */ #dialog { height: 200px; width: 400px; background-color: #EAF6DB; border: 1px solid lightslategray; position: absolute; } /* dialog window title section */ .dialog-title { height: 40px; line-height: 40px; background-color: #3a3333; cursor: move; } /* dialog window title inner detail */ .login, .close { display: inline-block; margin: 0 15px; } </style> <script> window.onload = function () { // 獲取DOM元素 var oDialog_title = document.getElementById( 'dialog-title' ); // 容許點擊鼠標獲取拖拽事件區域 var oDialog = oDialog_title.parentNode; // 登陸窗口 // 初始化 `登陸窗口` 默認居中位置 start // 獲取當前文檔可視區寬度和高度 var iScreenHeight = document.documentElement.clientHeight; // 可視區高度 var iScreenWidth = document.documentElement.clientWidth; // 可視區寬度 // 獲取當前 `登陸窗口` 寬度和高度 var iCurrentDialogHeight = oDialog.offsetHeight; // 窗口高度 var iCurrentDialogWidth = oDialog.offsetWidth; // 窗口寬度 // 計算保存初始化後 `登陸窗口` 的默認垂直水平居中位置 var iCurrentDialogTop = parseInt( ( iScreenHeight / 2 ) - ( iCurrentDialogHeight / 2 ) ); var iCurrentDialogLeft = parseInt( ( iScreenWidth / 2 ) - ( iCurrentDialogWidth / 2 ) ); // 修改 `登陸窗口` 默認位置 oDialog.style.top = iCurrentDialogTop + 'px'; oDialog.style.left = iCurrentDialogLeft + 'px'; // 初始化 `登陸窗口` 默認居中位置 end // 初始化當前滾動條滾動距離 var iCurrentScrollTop = 0; // 初始化當前 `登陸窗口` 應該滾動距離 var iRealTimeTop = 0; // 計算當前滾動條滾動距離 window.onscroll = function () { // 兼容寫法獲取當前滾動條滾動距離 iCurrentScrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 直接這麼改變top值, 會出現抖動, 這樣感受太生硬, 體驗也不太好 // oDialog.style.top = iCurrentDialogTop + iCurrentScrollTop + 'px'; // 當前 `登陸窗口` 應該實時滾動距離 iRealTimeTop = iCurrentDialogTop + iCurrentScrollTop; // 爲了防止出現抖動, 這樣感受也不太生硬, 優化體驗能夠採用緩衝運動方式 fnBufferMotion( oDialog, iRealTimeTop ); }; // 初始化鼠標默認位置 var iDisX = 0; var iDisY = 0; // 爲獲取到的DOM元素添加鼠標按下事件 `onmousedown` oDialog_title.onmousedown = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 距離計算鼠標位於彈出框內的位置 iDisX = oEvent.clientX - oDialog.offsetLeft; // 鼠標X軸位置 - 彈出框X外左邊距 iDisY = oEvent.clientY + iCurrentDialogTop - oDialog.offsetTop; // 鼠標Y軸位置 + 當前滾動條滾動距離 - 彈出框Y外上邊距 console.log( iCurrentDialogTop ); // 點擊彈出框後拖動鼠標, 移動彈出框 document.onmousemove = function ( ent ) { // 保存鼠標事件對象 var oEvent = ent || event; // 優化填坑 - 禁止 `登陸窗口` 拖拽出文檔可視區域, 保存 `登陸窗口` 在文檔中具體位置 var iCurrentDialogDisLift = oEvent.clientX - iDisX; // `登陸窗口` 當前位置於X軸具體值 var iCurrentDialogDisTop = oEvent.clientY + iCurrentDialogTop - iDisY; // `登陸窗口` 當前位置於Y軸具體值 // 檢測當前 `登陸窗口` X軸是否位於文檔可視區域最左側或最右側 if ( iCurrentDialogDisLift < 0 ) { iCurrentDialogDisLift = 0; } else if ( iCurrentDialogDisLift > document.documentElement.clientWidth - oDialog.offsetWidth ) { // 當前文檔X軸可視區域大小包括左右邊框線寬度 - `登陸窗口` X軸區域大小包括左右邊框線寬度 iCurrentDialogDisLift = document.documentElement.clientWidth - oDialog.offsetWidth; } // 檢測當前 `登陸窗口` Y軸是否位於文檔可視區域 + 當前滾動條滾動距離 的最上端或最下端 if ( iCurrentDialogDisTop < iCurrentScrollTop ) { iCurrentDialogDisTop = iCurrentScrollTop; } else if ( iCurrentDialogDisTop > document.documentElement.clientHeight + iCurrentScrollTop - oDialog.offsetHeight ) { // 當前文檔Y軸可視區域大小包括上下邊框線寬度 + 當前滾動條滾動距離 - `登陸窗口` Y軸區域大小包括上下邊框線寬度 iCurrentDialogDisTop = document.documentElement.clientHeight + iCurrentScrollTop - oDialog.offsetHeight; } // 當鼠標移動時改變彈出框的位置 oDialog.style.left = iCurrentDialogDisLift + 'px'; oDialog.style.top = iCurrentDialogDisTop + 'px'; }; // 當點擊鼠標拖動彈出框, 擡起鼠標時 document.onmouseup = function () { // 清除彈出框的移動事件及自己 document.onmousemove = null; document.onmouseup = null; }; // 阻止默認事件, 若是不加這個阻止默認事件, 在firefox下會有一個獲取焦點的光標一直在閃動, 在3.0及如下會出現拖動出現重影的狀況 return false; }; }; // 初始化定義器 var oTimer = null; /** * 緩衝運動 * @param oElement 運動對象 * @param iTarget 目標位置或者說目標點 */ function fnBufferMotion( oElement, iTarget ) { // 首先就是清除定時器, 由於當下面開啓定時器以前禁止存在還有再執行的定時器, 要否則會存在問題, 你能夠驗證一下 clearInterval( oTimer ); // 開啓定時器 oTimer = setInterval( function () { // 緩衝運動速度 var iSpeed = ( iTarget - oElement.offsetTop ) / 8; // 緩衝運動速度取整 iSpeed = iSpeed > 0 ? Math.ceil( iSpeed ) : Math.floor( iSpeed ); // 判斷是否緩衝運動到目標點, 是就關閉定時器, 不然就接着運動唄 if ( iTarget == oElement.offsetTop ) { clearInterval( oTimer ); // 關閉定時器 } else { oElement.style.top = oElement.offsetTop + iSpeed + 'px'; // 緩衝運動改變 `登陸窗口` 的上外邊距 } }, 30 ); } </script> </head> <body style="height: 4000px;"> <!-- 假設這個DIV就是一個登陸窗口 --> <div id="dialog"> <div id="dialog-title" class="dialog-title clearfix"> <span class="fl-l login">登陸</span> <span class="fl-r close">X</span> </div> </div> </body> </html>
至於添加模態框, 就是當出現
登陸窗口
時禁止滾動這種方法你能夠試着實現一下!
Github: JavaScript實現【網易雲音樂Web站登陸窗口】拖拽功能網站
以上就是實現與網易雲音樂
Web站登陸窗口
拖拽效果一致的具體過程但願本文對你的工做和學習有所幫助spa
若是以爲還不錯怎麼感謝我呢? 媽呀! 點贊啊!firefox
Good Luck! from warnerwu at 2017.08.19 AM3d