前言
近期有個項目需求,需要用到拖動事件。由於不需要考慮IE8等低端瀏覽器的兼容性, 所以想到HTML5中的drag
事件, 但是發現移動端 android & IOS
並不支持 drag
事件。所有新事物的產生都不是偶然, 所以決定自己去實現一個頁面元素的拖動。
實現頁面元素的主要思路,是通過監聽事件(touchstart
)判斷要拖動的元素並定位該元素; 然后監聽移動事件(touchmove
)判斷手指移動的方向距離並將這些參數轉換為元素的移動方向距離,通過 transform
(當然也可以通過定位top&left
等)移動元素; 當然有開始就有停下來,所以還要監聽結束(touchend
)事件,在結束的時候進行相應的處理,返回初始位置,或者停在結束的位置。
現在整體思路有了,然后就是一步步的實現。
demo (請在移動端打開或者模擬移動端打開)
手機請掃
js實現拖動操作
初始化
就像蓋房子需要打地基一樣,寫程序實現一個功能需要初始化。
初始化主要是對傳入參數處理,然后做一些基本定義。在這里實現的拖動操作, 以將頁面元素拖入垃圾箱為背景來進行一系列的操作。
首先, 我們需要定義可操作的元素,即需要被拖動的元素。接下來就是對可操作元素進行操作,這里需要綁定事件,也就是touch事件,包括 touchstart/touchmove/touchend
。在對應的事件內進行相應的操作,從而完成拖動
事件綁定
初始化之后,我們就需要對可操作元素進行事件的綁定,
先上代碼,以下分別是對應touch事件以及對應的操作
Drag.prototype.touchstart = function(e) {
e.preventDefault();
e.stopPropagation();
var tar = e.target;
//執行定義在拖動開始時須執行的函數, 參數為即將拖動的元素
this.opts.onStart(tar);
//初始化拖動元素的位置信息;
this.dragT = tar.offsetTop;
this.dragL = tar.offsetLeft;
this.dragW = tar.offsetWidth || tar.clientWidth;
this.dragH = tar.offsetHeight || tar.clientHeight;
//定義開始移動位置
this.startX = e.pageX || e.touches[0].pageX;
this.startY = e.pageY || e.touches[0].pageY;
//重置移動參數
this.moveX = this.moveY = 0;
}
Drag.prototype.touchmove = function(e) {
var tar = e.target;
this.opts.onMove(tar);
this.nowX = e.pageX || e.touches[0].pageX;
this.nowY = e.pageY || e.touches[0].pageY;
//計算目標元素需移動的距離
this.moveX = this.nowX - this.startX;
this.moveY = this.nowY - this.startY;
//檢測是否越界,並調整
this.checkOver(this.moveX, this.moveY);
//進行拖動元素移動操作
this.setMove(tar);
//檢測是否落入目標位置
this.checkPos('move', tar);
}
Drag.prototype.touchend = function(e) {
//目標區域的視覺變化
this.tarEle.style.cssText = "opacity: .5;"
//檢測最終位置
this.checkPos('end', e.target);
}
注:以上代碼是基於將元素拖入垃圾箱的相應事件函數,可根據自己項目情況進行調整,這里提供思路。
有了事件監聽,探知了我們手指觸摸、移動、抬起等,我們要將對應的操作實現到頁面內的元素,便需要一個移動元素的操作,便是上邊的 setMove
函數(以下方法使用前確定你的瀏覽器支持)
Drag.prototype.setMove = function(e, type) {
var x = this.moveX || 0,
y = this.moveY || 0;
if(type === 'reset') {
e.style.cssText = '';
return;
}
e.style.cssText += 'position: absolute;-webkit-transform: translate('+x+'px,'+y+'px);';
}
沒錯就是簡單粗暴的調整 css
來實現移動元素
當然再加上驗證元素是否越界(這個界限根據自己情況指定,可以在自己設定的一個盒模型內,也可以是整個屏幕,根據自己情況而定,這里不貼代碼)
因為我這里有個垃圾桶,所以需要判斷拖動元素是否落入垃圾桶,然后進行后續操作
Drag.prototype.checkPos = function(type, e) {
//判斷拖動元素是否到達目標位置,判斷方式更具情況而定,此處判斷的依據是:touch事件位置判斷,即結束時touch的位置是否在目標區域位置
if(this.nowX > this.tarL && this.nowX < this.tarL + this.tarW && this.nowY > this.tarT && this.nowY < this.tarT + this.tarH) {
//進入目標區域
if(type === 'move' && !!this.opts.tarEle) {
//在移動過程中,進入目標區域
this.opts.onMoveIn(this.tarEle);
} else {
//在拖動結束時進入目標區域
this.opts.onEnd(e);
}
} else {
//落在目標區域外的情況
this.tarEle.style.cssText = "opacity: .5;"
if(type === 'end'){
this.resetFun(e);
}
}
}
致此整個移動過程都已實現
此處只是指出思路,具體執行過程根據自己的項目情況進行相應的調整