日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

JavaScript 實現拖拽效果組件功能(兼容移動端)

瀏覽:203日期:2023-10-08 16:38:33

頁面元素拖拽是一種非常實用的前端效果,基于元素拖拽可以實現很多不同的功能,增加客戶端許多操作的便捷性,大大提高用戶體驗。日常生活中大家多多少少都見過這種效果,所以就不廢話了,直接開干吧。

預期目標

實現一個 Class 類,通過該 Class,可以將任意 DOM 元素(比如 div)一鍵變為可拖拽狀態,也可以恢復成原來的狀態,例如這樣:

<!DOCTYPE html><html lang='en'><head> <meta charset='UTF-8'> <meta name='viewport' content='width=device-width, initial-scale=1.0'> <title>Document</title> <style> #box1 { height: 50px; width: 50px; background-color: cadetblue; } #box2 { height: 50px; width: 50px; background-color: blue; } #box3 { height: 50px; width: 50px; background-color: red; } </style></head><body> <div id='box1'>1</div> <a id='box2'>2</a> <div id='box3'>3</div></body><script type='module'>// 我們要完成的目標 Class import DragElement from ’./DragElement.js’ // 使 3 個元素可拖拽 let box1 = new DragElement(document.querySelector('#box1')) let box2 = new DragElement(document.querySelector('#box2')) let box3 = new DragElement(document.querySelector('#box3')) // box2 解除拖拽效果,恢復為原來的樣子 // box2.dragRelease()</script></html>

原本的樣子

JavaScript 實現拖拽效果組件功能(兼容移動端)

隨意拖放

JavaScript 實現拖拽效果組件功能(兼容移動端)

一、算法思路

1.1 拖拽的行為描述

我們先思考如何描述拖拽這一行為。我的思路是這樣的:

先對拖拽這一行為進行定義:在指定的元素上,若保持鼠標按下狀態,則該元素將會跟隨鼠標移動。當鼠標松開,該元素將不再跟隨鼠標移動。如果是移動端的話,鼠標的角色改為觸摸(touch)即可。

根據定義,我們可以確定幾個關鍵信息:

鼠標移動,是拖拽算法本身的作用范圍。 鼠標按下,開啟拖拽 鼠標松開,關閉拖拽

可以看到,完整的拖拽功能分為 3 個部分,分別是開啟、運行與關閉。分別對應鼠標的按下、運行、松開事件。 因此我們至少需要設計相應的 3 個函數,作為事件的回調。在這里我分別命名為 dragStart()、dragMoving()、dragEnd()。

這里就出現了第一個重點:如何描述拖拽功能的狀態變化?

顯然,鼠標的按下與松開,將會決定DOM 元素是否能夠被拖拽,這是一種 “狀態” 的變化。這種狀態的變化,在編碼上,可以通過一個變量來實現,也可以通過不斷地添加 or 移除回調函數來實現。如果通過變量的話,在鼠標沒有按下時,鼠標移動事件也會觸發進行狀態判斷,這其實是沒有必要的,因此方案上我們選擇后者,鼠標按下與松開時,分別添加和移除實現拖拽的函數。

以上是拖拽本身的行為,此外,由于我們需要 DOM 元素能夠在原本的狀態和可拖拽狀態之間進行轉換,因此我們還需要 2 個函數,一個用于將 DOM 元素變為可拖拽狀態,另一個用于卸載這些狀態。前者我稱為 dragActive(),后者我稱為 dragRelease()。它們做的事情,就是添加和解除事件監聽。

現在第一個問題解決了,我們來解決第二個問題,那就是:拖拽函數怎么實現?

1.2 拖拽的實現

首先看核心的,拖拽本身應該怎么計算,如何讓元素跟著鼠標走。

同樣的,我們繼續想象實際的場景。鼠標按下時,我們假設鼠標的坐標處于(x0, y0) 點,鼠標移動,假設移動到了(x1, y1) 點。那么該元素,相對自身初始位置便移動了(x1-x0, y1-y0) 的距離。這種相對于自身移動的,在 CSS 上可以通過相對定位,也可以通過 transform: translate 或 translate3d 來實現,由于定位在布局中很常用,我們也不知道指定的 DOM 元素到底是什么樣式,為了盡量不影響原來的布局,所以我們采用 transform。

再回到具體計算上,鼠標的位置 x 和 y,可以通過事件回調函數傳入的參數 event 得到,在 PC 端是 event.clientX 和 event.clientY,移動端是 event.changedTouches[0].pageX 和 event.changedTouches[0].pageY。而 mousemove 事件是連續觸發的,我們的拖動也要讓元素跟著鼠標連續運動,因此需要不停更新 (x0, y0),(x1, y1) 的值,在每個細小的運動中都進行差值計算,就像微積分一樣。為了方便記錄和更新,我們不妨把拖動中需要的變量用一個對象表示,稱為 dragInfo,掛載到 document 元素上,這樣在不同的函數、對象之間都可以訪問。

class DragElement { constructor(element) { this.element = element document.dragInfo = { element: this.element, x0: 0, y0: 0, x1: 0, y1: 0 } }}

element 表示拖拽的元素,x 和 y 分別為計算所需的變量。

獲取鼠標位置的函數:

updateDragPosition = (event) => {return {x: event.clientX || (event.changedTouches ? event.changedTouches[0].pageX : document.dragInfo.x0),y: event.clientY || (event.changedTouches ? event.changedTouches[0].pageY : document.dragInfo.y0)}}

或許有人會有疑問,為啥不直接 event.clientX || event.changedTouches[0].pageX,而是要用三元表達式。這是因為有些情況下,上述兩者可能都不存在,比如當鼠標移到瀏覽器左邊緣的時候,就無法獲得位置:

JavaScript 實現拖拽效果組件功能(兼容移動端)

獲取鼠標位置的函數寫完后,就可以寫拖拽的函數了:

dragMoving = (event) => {document.dragInfo.x1 = this.updateDragPosition(event).x - document.dragInfo.x0 + document.dragInfo.x1document.dragInfo.y1 = this.updateDragPosition(event).y - document.dragInfo.y0 + document.dragInfo.y1document.dragInfo.x0 = this.updateDragPosition(event).xdocument.dragInfo.y0 = this.updateDragPosition(event).ydocument.dragInfo.element.style.transform = ’translate3d(’ + document.dragInfo.x1 + ’px, ’ + document.dragInfo.y1 + ’px, 0)’;}

但此時問題就來了,由于 document 上只有一個 dragInfo,不同的組件之間坐標沖突如何解決?其實這個簡單,只需要在 this.element 上添加一個對象記錄每次拖拽后的位置即可,每當點擊一個拖拽元素時,就將該元素的信息注入 document.dragInfo。

this.element.dragPostion = {x: 0,y: 0}

綜上,我們已經解決了最核心的流程描述與算法部分,接下來只要編碼就可以了。

二、編碼實現

請根據之前說的思路,自行閱讀代碼,整體邏輯還是非常清晰的,如果有一些細節不懂,可以在評論區提出,或者我有空了再補充。

class DragElement { constructor(element) { this.element = element document.dragInfo = { element: this.element, x0: 0, y0: 0, x1: 0, y1: 0 } document.updateDragPosition = this.updateDragPosition this.dragActive() } // 更新鼠標位置 updateDragPosition = (event) => { return { x: event.clientX || (event.changedTouches ? event.changedTouches[0].pageX : document.dragInfo.x0), y: event.clientY || (event.changedTouches ? event.changedTouches[0].pageY : document.dragInfo.y0) } } // 為元素配置相應的拖拽控制函數 dragActive = () => { if (!this.element) return this.element.style.display = 'block' this.element.addEventListener(’mousedown’, this.dragStart, false) this.element.addEventListener(’touchstart’, this.dragStart, false) this.element.addEventListener(’mouseup’, this.dragEnd, false) // 釋放 this.element.addEventListener(’touchend’, this.dragEnd, false) this.element.addEventListener(’touchcancel’, this.dragEnd, false) // 為該元素添加一個對象,保存當前位置 this.element.dragPostion = { x: 0, y: 0 } } // 釋放配置 dragRelease = () => { this.element.removeEventListener(’mousedown’, this.dragStart) this.element.removeEventListener(’touchstart’, this.dragStart) this.element.removeEventListener(’mouseup’, this.dragEnd) // 釋放 this.element.removeEventListener(’touchend’, this.dragEnd) this.element.removeEventListener(’touchcancel’, this.dragEnd) this.element.style.display = '' return this.element } // 點擊捕獲拖拽元素,初始化相應信息 dragStart = (event) => { document.dragInfo.element = this.element document.dragInfo.x0 = this.updateDragPosition(event).x document.dragInfo.y0 = this.updateDragPosition(event).y document.dragInfo.x1 = this.element.dragPostion.x document.dragInfo.y1 = this.element.dragPostion.y // 屏蔽默認行為 event.preventDefault(); // mousemove 綁定在 document 上,防止鼠標過快可能導致的元素跟丟 document.addEventListener(’mousemove’, this.dragMoving, false) document.addEventListener(’touchmove’, this.dragMoving, false) } // 實時計算、更新相對位置變化 dragMoving = (event) => { document.dragInfo.x1 = this.updateDragPosition(event).x - document.dragInfo.x0 + document.dragInfo.x1 document.dragInfo.y1 = this.updateDragPosition(event).y - document.dragInfo.y0 + document.dragInfo.y1 document.dragInfo.x0 = this.updateDragPosition(event).x document.dragInfo.y0 = this.updateDragPosition(event).y document.dragInfo.element.style.transform = ’translate3d(’ + document.dragInfo.x1 + ’px, ’ + document.dragInfo.y1 + ’px, 0)’; } // 關閉拖拽 dragEnd = () => { // 保存當前位置 this.element.dragPostion.x = document.dragInfo.x1 this.element.dragPostion.y = document.dragInfo.y1 // 解綁 document.removeEventListener(’touchmove’, this.dragMoving) document.removeEventListener(’mousemove’, this.dragMoving) }}export default DragElement

到此這篇關于JavaScript 實現拖拽效果組件功能(兼容移動端)的文章就介紹到這了,更多相關JavaScript 拖拽效果組件內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩不卡一二三区| 国产精品日本一区二区三区在线| 麻豆国产欧美日韩综合精品二区| 免费看久久久| 国产日韩精品视频一区二区三区| 日本一不卡视频| 免费在线观看一区| 国产在线一区不卡| 久久国产小视频| 亚洲www免费| 高清精品久久| 国产91在线播放精品| 精品入口麻豆88视频| 六月婷婷一区| 中文一区一区三区高中清不卡免费| 日日夜夜免费精品| 香蕉精品视频在线观看| 久久九九精品| 99成人在线视频| 99视频精品全部免费在线视频| 欧美一级专区| 日韩一二三区在线观看| 99成人在线| 日本 国产 欧美色综合| 欧美黄页在线免费观看 | 视频在线观看一区| 日本欧美在线| 国产精品探花在线观看| 午夜av不卡| 亚洲一区欧美激情| 日韩精品乱码av一区二区| 亚洲一区欧美二区| 日韩啪啪电影网| 黄色国产精品| 久久国产婷婷国产香蕉| 国产精品yjizz视频网| 午夜在线观看免费一区| 精品国产一区二区三区av片| 日韩亚洲在线| 麻豆国产精品| 蜜臀精品久久久久久蜜臀| 欧美日韩国产观看视频| 免费看精品久久片| 麻豆91小视频| 亚洲人成毛片在线播放女女| 捆绑调教美女网站视频一区| 天堂精品久久久久| 亚洲欧美激情诱惑| av在线资源| 日韩专区精品| 久久男女视频| 亚洲深夜视频| 精品国产18久久久久久二百| 久久中文字幕一区二区| 欧美日本精品| 丝袜美腿成人在线| 国产精品日本| 精品91福利视频| 激情91久久| 成人看片网站| 宅男在线一区| 国产精品久久久久久妇女 | 久久精品99国产精品日本| 日韩视频一区| 亚洲欧美不卡| 亚洲一卡久久| 亚洲三级视频| 亚洲精品亚洲人成在线观看| 久久在线免费| 精品成人免费一区二区在线播放| 日本视频中文字幕一区二区三区| 五月婷婷亚洲| 女人av一区| 亚洲黄页一区| 欧美精选一区二区三区| 国产在线|日韩| 日本久久黄色| 最新日韩欧美| 偷拍欧美精品| 性一交一乱一区二区洋洋av| 午夜久久久久| 女人天堂亚洲aⅴ在线观看| 色在线中文字幕| 国产精品日韩| 偷拍亚洲精品| 亚洲欧洲美洲av| 国产精品1区| 水蜜桃久久夜色精品一区| 日本成人手机在线| 91大神在线观看线路一区| 亚洲一级大片| 最新亚洲国产| 欧美一区自拍| 国产在线观看91一区二区三区| 天堂av在线| 久久国产99| 精品视频网站| 欧美影院三区| 国产精品1区| 日韩免费视频| 欧美日韩视频免费观看| 久久天堂精品| 久久久9色精品国产一区二区三区| 欧美sss在线视频| 亚洲a成人v| 色网在线免费观看| 亚洲精品一级| 麻豆国产精品一区二区三区 | 国产精品入口久久| 色婷婷久久久| 日韩av一区二区三区四区| 久久天堂影院| 欧美亚洲精品在线| 四虎在线精品| 久久精品导航| 国产伦理久久久久久妇女| 快播电影网址老女人久久| 午夜一级在线看亚洲| 九九九精品视频| 欧美亚洲一区二区三区| 日本一区二区三区视频在线看| 成人免费电影网址| 国产综合色区在线观看| 日韩视频二区| 国产日韩一区二区三免费高清| 日韩精品1区| 国产精品一区二区中文字幕| 日韩成人精品一区| 91成人精品| 视频一区在线播放| 日韩精品视频中文字幕| 日韩欧美久久| 国产精品99精品一区二区三区∴ | 久久久国产精品网站| 国产精品伦一区二区| 精品久久免费| 欧美激情另类| 中文一区二区| 亚洲精品激情| 久久国产主播| 国产亚洲一区二区手机在线观看 | 亚洲黄色在线| 亚洲a成人v| 久久国内精品视频| 成人三级高清视频在线看| 免费视频国产一区| 亚洲麻豆一区| 精品成人18| 日韩激情视频网站| 中文字幕人成乱码在线观看| 黄色成人91| 国产欧美日韩一区二区三区四区| 国产一区二区亚洲| 亚洲aa在线| 日韩中文字幕不卡| 91精品国产自产观看在线| 国产精品一国产精品| 精品日韩一区| 亚洲高清毛片| 亚洲三级视频| 日本一区二区免费高清| 欧美日韩高清| 97se亚洲| 国产99久久久国产精品成人免费| 国产一区视频在线观看免费| 亚洲资源网站| 国产精品久久久久77777丨| 另类小说一区二区三区| 亚洲精品网址| 国产精品自拍区| 亚洲激情中文| 国产成人免费| 国产亚洲欧美日韩在线观看一区二区| 麻豆理论在线观看| 偷拍欧美精品| 欧洲av不卡| 久久精品一区| 国产亚洲精aa在线看| 欧美女激情福利| 日韩av二区| 美女久久99| 免费在线观看不卡| 亚洲黄色免费av| 日韩av中文在线观看| 欧美va天堂在线| 成人午夜在线| 青青国产精品| 蜜桃一区二区三区在线观看| 97人人精品| 精品黄色一级片| 欧美亚洲一级| 国产精品天堂蜜av在线播放| 亚洲一区二区av| 国产一区二区三区自拍| 日韩av片子| 都市激情国产精品| 久久激情五月婷婷| 亚洲一级淫片| 午夜一区在线| 性色一区二区|