原生js實現拖拽功能
在前端技術日新月異,飛速發展的當下,湧現出了很多優秀的開源框架以及優秀的開源元件,這些都是優秀的前端開發者的技術成果。當然,雖然有這麼多現成的開源技術成果供我們再開發中使用,但我們不能僅抱著拿來主義的態度,只顧拿來用就行,更多的是要以學習的心態來對待開源技術,對待前端世界,要多汲取他(她)人的經驗,且又不忘根本(基礎知識),站在巨人的肩膀上繼續前行!
js拖拽功能
拖拽功能是前端很多業務場景都能使用到的一種普遍的技術,比如彈窗視口的拖拽等,前端世界的很多優秀框架元件都擁有封裝完美的拖拽功能,別人封裝的優秀原始碼,健壯,穩定,同時又優雅美觀,自然是值得我們去學習的。這篇文章主要講解下如何用原生js實現一個簡單的拖拽功能。
拖拽原理
對於PC端來說,拖拽功能無非就是滑鼠點選,滑鼠開始移動,滑鼠鬆開三個步驟,當然這三個步驟裡面有拆分了很多的細節,越是健壯,穩定的程式碼,對細節的處理就越嚴謹(我們主要講實現一個簡單的拖拽功能,可能有些細節處理得不妥當,待以後再次進行封裝)。
滑鼠點選:當滑鼠按下點選的時候,需要拖拽的容器就已應該準備就緒 進去拖拽狀態了
滑鼠移動:需要拖拽的容器根據滑鼠的移動位置而移動,這裡面就包含的很多對細節的處理,如:當容器某一端的位置到達了瀏覽器邊緣的時候,是不應該超出瀏覽器範圍區域的,不然會撐出滾動條或者被遮擋,這不是一個很好的效果。那麼要如何把容器的位置控制在瀏覽器規定的範圍區域呢?這裡就要分別處理上下左右四個方向的位置變化。
1.top端:當容器的頂部到達了瀏覽器頂部邊緣的時候,滑鼠移動的方向繼續是向上移動,那麼就要設定容器頂端的top值始終為0,保證容器位置不會溢位瀏覽器範圍。
2.bottom端:當容器的底部到達了瀏覽器底部邊緣的時候,滑鼠移動的方向繼續是向下移動,那麼就要設定容器底端的bottom值始終為瀏覽器可視區域的高度值減去容器的高度值,保證容器位置不會溢位瀏覽器範圍。
3.left端:當容器的左端到達了瀏覽器左端邊緣的時候,滑鼠移動的方向繼續是向左移動,那麼就要設定容器頂端的left值始終為0,保證容器位置不會溢位瀏覽器範圍。
3.right端:當容器的右端到達了瀏覽器右端邊緣的時候,滑鼠移動的方向繼續是向右移動,那麼就要設定容器頂端的right值始終為瀏覽器可視區域的寬度值減去容器的寬度值,保證容器位置不會溢位瀏覽器範圍。滑鼠鬆開:代表著容器拖拽結束,停止改變容器的位置。這裡也有個小細節需要注意下,就是,滑鼠點選容器準備拖拽時候的位置要和滑鼠鬆開後滑鼠在容器中的位置是一致的,意思就是在拖拽的過程當中不管滑鼠的位置在什麼地方,停止拖拽後都要回到原點。
介面引數暴露
完美的封裝往往都是需要搭配強大的配置引數來維護它的健壯,穩定的。
對於拖拽功能,需要配置的引數通常需要有以下內容:
需要拖拽的容器(必選)
需要拖拽的區域(可選)
是否可拖拽,拖拽開關(可選)
是否需要虛擬拖拽容器(可選)
控制虛擬拖拽容器的樣式(可選)
配置上這些引數,一個簡單的拖拽功能就可以使用了。
拖拽示例核心程式碼
呼叫方式
new DragView({
"dragWrap": document.getElementById("drag_wrap"), //容器,必選
"dragableArea": document.getElementById("drag_area"), //可拖拽區域,可選
"isDrag": true, //是否可拖拽,可選
"isDummyWrap": true, //是否需要虛擬拖拽框,可選
"dummyWrapClass": "dragview_dummy_wrap2" //控制虛擬拖拽框的樣式,可選
})
封裝的部分程式碼
DragView.prototype = {
"constructor": DragView,
"init": function(){
var that = this;
var dragMove = document.createElement("div");
dragMove.setAttribute("class","dragview_move");
document.body.appendChild(dragMove);
that.options.isDrag && (that.options.dragableArea.style.cursor = "move");
that.options.dragableArea.onmousedown = function(e){
if(!that.options.dragStatus){
that.throttle(function(){
that.options.isDrag && that.mouseDown(e);
},null,0);
}
}.bind(that);
},
"getEvent": function(e){
return e ? e : window.event;
},
"extend": function(setting,option){
for(var attr in setting){
if(typeof option[attr] != "undefined"){
setting[attr] = option[attr];
}
}
return setting;
},
"throttle": function(fn,context,delay){
clearTimeout(fn.timeoutId);
fn.timeoutId = setTimeout(function(){
fn.call(context);
},delay);
},
"mouseDown": function(e){
var that = this;
var dragMoveArea = "";
var dragWrap = that.options.dragWrap;
var events = that.getEvent(e);
var disX = events.clientX - dragWrap.offsetLeft;
var disY = events.clientY - dragWrap.offsetTop;
document.getElementsByClassName("dragview_move")[0].style.display = "block";
dragWrap.style.position = "absolute";
dragWrap.style.zIndex = "99999";
that.options.tempDragWrap = that.options.dragWrap;
if(that.options.isDummyWrap){
dragMoveArea = document.createElement("div");
dragMoveArea.setAttribute("class",that.options.dummyWrapClass);
dragMoveArea.style.width = dragWrap.clientWidth + "px";
dragMoveArea.style.height = dragWrap.clientHeight + "px";
dragMoveArea.style.position = "absolute";
dragMoveArea.style.zIndex = "99999";
dragMoveArea.style.top = dragWrap.style.top;
dragMoveArea.style.left = dragWrap.style.left;
document.body.appendChild(dragMoveArea);
that.options.tempDragWrap = dragMoveArea;
}
that.options.dragStatus = true;
document.onmousemove = function(e){
that.throttle(function(){
var _events = that.getEvent(e);
that.mouseMove(_events,disX,disY,dragMoveArea);
},null,0);
}
document.onmouseup = function(){
that.options.dragStatus && that.mouseUp(dragMoveArea);
}
},
"mouseMove": function(_events,disX,disY,dragMoveArea){
if(this.options.dragStatus){
var _x = _events.clientX - disX;
var _y = _events.clientY - disY;
var _winW = document.documentElement.clientWidth || document.body.clientWidth;
var _winH=document.documentElement.clientHeight || document.body.clientHeight;
var option = {
"x": _x,
"y": _y,
"winX": _winW,
"winY": _winH,
"dragW": this.options.tempDragWrap.offsetWidth,
"dragH": this.options.tempDragWrap.offsetHeight
};
this.limiteRange(option);
}
},
"mouseUp": function(dragMoveArea){
this.options.dragWrap.style.left = this.options.tempDragWrap.style.left;
this.options.dragWrap.style.top = this.options.tempDragWrap.style.top;
this.options.dragStatus = false;
dragMoveArea!="" && document.body.removeChild(dragMoveArea);
document.getElementsByClassName("dragview_move")[0].style.display = "none";
},
"limiteRange": function(option){
if(option.x <= 0 || option.dragW >= option.winX){
this.options.tempDragWrap.style.left = "0px";
}else if((option.x + option.dragW) >= option.winX){
this.options.tempDragWrap.style.left = (option.winX - option.dragW) + "px";
}else{
this.options.tempDragWrap.style.left = option.x + "px";
}
if(option.y <= 0 || option.dragH >= option.winY){
this.options.tempDragWrap.style.top = "0px";
}
else if((option.y + option.dragH) >= option.winY){
this.options.tempDragWrap.style.top = (option.winY - option.dragH) + "px";
}
else{
this.options.tempDragWrap.style.top = option.y + "px";
}
}
};
顯示效果如下連結:https://webproblem.github.io/hello-world/drag-View/drag.html
具體示例及原始碼見我的 github , ** 如果喜歡,請記得Star哈!**
原創文章,站在前輩們的經驗上的總結,文中如有不正之處,還望指正!
相關文章
- 原生實現元素的拖拽
- 用原生 JS 實現 innerHTML 功能JSHTML
- 原生JS拖拽效果JS
- 原生js實現商品排序功能JS排序
- vuejs2.0使用Sortable.js實現的拖拽功能VueJS
- 原生js拖拽功能製作滑動條例項教程JS
- [WPF]原生TabControl控制元件實現拖拽排序功能控制元件排序
- 實現小程式canvas拖拽功能Canvas
- Ext實現資料拖拽功能
- angualr實現滑鼠拖拽排序功能排序
- 使用原生js實現選項卡功能例項教程JS
- 如何使用原生 JS 實現一個文字劃線功能JS
- 用原生JS實現 圖片輪播切換 功能JS
- RecyclerView 實現滑動刪除和拖拽功能View
- RecyclerView實現滑動刪除和拖拽功能View
- 原生JS實現你畫我猜的一點點功能JS
- 原生js實現replace方法JS
- 前端基礎功能,原生js實現輪播圖例項教程前端JS
- JS原生實現觀察者模式JS模式
- 原生js實現輪播圖JS
- 原生JS實現影片截圖JS
- 原生JavaScript實現AJAX、JSONPJavaScriptJSON
- 實現element-ui對話方塊可拖拽功能UI
- js拖拽原理及簡單實現(渣渣自學)JS
- 原生 JS 擼一個輪播圖(支援拖拽切屏)JS
- 用原生js手寫實現promiseJSPromise
- 原生JS實現二級聯動JS
- 原生JS實現頁面內定位JS
- 原生js實現發簡訊~chatJS
- JS實現線上ps功能JS
- js實現複製功能JS
- Vue 結合 echarts 原生 html5 實現拖拽排版報表系統VueEchartsHTML
- iOS - 利用原生框架實現掃一掃功能iOS框架
- C#影象顯示實現拖拽、錨點縮放功能【轉】C#
- 原生js實現購物車結算JS
- 原生 js 實現一個前端路由 routerJS前端路由
- JS原生實現表單序列化JS
- 原生JS實現貼上到剪貼簿JS