今天來研究下跟拖拽有關的問題,以備以後可以實現更多友好的互動形式。
1. 相關原生方法:
- ondragstart:拖拽開始
- ondragend:拖拽結束
- ondragenter:拖拽元素進入目標元素頭上的時候
- ondrop:拖拽元素進入目標元素頭上,同時滑鼠鬆開的時候
- ondragover:拖拽元素在目標元素頭上移動的時候
有點暈?按下面的例子分別都操作下就明白啦。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type= text/css>
.container {
width: 400px;
height: 400px;
background: #ff6632;
}
</style>
</head>
<body>
<div id='drag1' draggable="true">拖拽我,come on!</div>
<div id='drag2'>拽不動我,come on!</div>
<div class='container' id='container'>
</div>
</body>
<script>
document.getElementById('drag1').ondragstart = function(){
console.log('開始拖拽')
}
document.getElementById('drag1').ondragend = function(){
console.log('結束拖拽')
}
document.getElementById('container').ondrop = function(){
console.log('已掉入規定範圍')
}
document.getElementById('container').ondragenter = function(){
console.log('拖拽元素進入目標元素頭上的時候')
}
document.getElementById('container').ondragover = function(ev) {
//防止ondrop不生效,ev.preventDefault()
ev.preventDefault();
console.log('拖拽元素在目標元素頭上移動的時候')
};
</script>
</html>
複製程式碼
特別注意:
- 想對一個元素進行一系列的拖拽操作,要註明屬性
draggable="true"
來啟用它的可拖拽性。 - 在使用ondrop時,發現沒有生效,在ondragover中需要阻止預設事件的觸發。
到這裡我們已經可以拖拽元素並且監聽一系列的拖拽事件了,然而本文遠遠沒有結束,我們接著往下看:
人家網頁上的拖拽都是拖著元素可以隨便動,我這寫的什麼玩意!元素根本都不能動,不好使啊!!!!
彆著急,現在我們來讓元素跟著拖拽動起來!!!
- 首先我們要搞清楚一些概念:
- 清楚了概念,我們看下具體實現。
html部分:
<style type='text/css'>
#box {
position: absolute;
left: 100px;
top: 100px;
padding: 5px;
background: #f0f3f9;
width: 100px;
height: 100px;
}
</style>
...
<div id='box'></div>
複製程式碼
js部分:
window.onload = function () {
var oBox = document.getElementById("box");
startDrag(oBox, oBox);
};
var params = {
left: 0,
top: 0,
currentX: 0,
currentY: 0,
flag: false
};
//獲取相關CSS屬性
var getCss = function (o, key) {
return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, null)[key];
};
//拖拽的實現
var startDrag = function (bar, target, callback) {
if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}
if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}
//o是移動物件
bar.onmousedown = function (event) {
params.flag = true;
var e = event;
params.currentX = e.clientX;
params.currentY = e.clientY;
};
document.onmouseup = function () {
console.log('test')
params.flag = false;
if (getCss(target, "left") !== "auto") {
params.left = getCss(target, "left");
}
if (getCss(target, "top") !== "auto") {
params.top = getCss(target, "top");
}
};
document.onmousemove = function (event) {
var e = event ? event : window.event;
if (params.flag) {
var nowX = e.clientX, nowY = e.clientY;
var disX = nowX - params.currentX, disY = nowY - params.currentY;
target.style.left = parseInt(params.left) + disX + "px";
target.style.top = parseInt(params.top) + disY + "px";
}
}
};
複製程式碼
元素跟著動起來啦!
可以嘗試把這裡的 DEMO 和 drag 的方法合併使用,這裡就不贅述啦。
上述為PC的拖動,我們把chrome的模擬器切到手機模式,oh myGod!!炫酷的效果全都失效了!!!!桑心~~~~
下面我們來看下移動端的拖拽操作:
在這之前先對touch事件有一個瞭解:學習連結
有一些不得不說的概念:
-
screenX: 觸控點相對於螢幕左邊緣的 x 座標。
-
screenY: 觸控點相對於螢幕上邊緣的 y 座標。
-
clientX: 觸控點相對於瀏覽器的 viewport左邊緣的 x 座標。不會包括左邊的滾動距離。
-
clientY: 觸控點相對於瀏覽器的 viewport上邊緣的 y 座標。不會包括上邊的滾動距離。
-
pageX: 觸控點相對於 document的左邊緣的 x 座標。 與 clientX不同的是,他包括左邊滾動的距離,如果有的話。
-
pageY: 觸控點相對於 document的左邊緣的 y 座標。 與 clientY不同的是,他包括上邊滾動的距離,如果有的話。
-
target: 總是表示 手指最開始放在觸控裝置上的觸發點所在位置的 element。即使已經移出了元素甚至移出了document, 他表示的element仍然不變
掌握了上述概念開啟控制檯,讓我來觀察元素的運動吧!!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
#content {
width: 200px;
height: 200px;
background: #ff6632;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="content">test</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
(function (window) { //傳入window,提高變數的查詢效率
function myQuery(selector) { //這個函式就是對外提供的介面。
//呼叫這個函式的原型物件上的_init方法,並返回
return myQuery.prototype._init(selector);
}
myQuery.prototype = {
/*初始化方法,獲取當前query物件的方法*/
_init: function (selector) {
if (typeof selector == "string") {
//把查詢到的元素存入到這個原型物件上。
this.ele = window.document.querySelector(selector);
//返回值其實就是原型物件。
return this;
}
},
/*單擊事件:
* 為了規避click的300ms的延遲,自定義一個單擊事件
* 觸發時間:
* 當抬起手指的時候觸發
* 需要判斷手指落下和手指抬起的事件間隔,如果小於500ms表示單擊時間。
*
* 如果是大於等於500ms,算是長按時間
* */
tap: function (handler) {
this.ele.addEventListener("touchstart", touchFn);
this.ele.addEventListener("touchend", touchFn);
var startTime,
endTime;
function touchFn(e) {
e.preventDefault()
switch (e.type) {
case "touchstart":
startTime = new Date().getTime();
break;
case "touchend":
endTime = new Date().getTime();
if (endTime - startTime < 500) {
handler.call(this, e);
}
break;
}
}
},
/**
* 長按
* @param handler
*/
longTag: function (handler) {
this.ele.addEventListener("touchstart", touchFn);
this.ele.addEventListener("touchmove", touchFn);
this.ele.addEventListener("touchend", touchFn);
var timerId;
function touchFn(e) {
switch (e.type) {
case "touchstart": //500ms之後執行
timerId = setTimeout(function () {
handler.call(this, e);
}, 500)
break;
case "touchmove":
//如果中間有移動也清除定時器
clearTimeout(timerId)
break;
case "touchend":
//如果在500ms之內抬起了手指,則需要定時器
clearTimeout(timerId);
break;
}
}
},
/**
* 左側滑動。
記錄手指按下的左邊,在離開的時候計算 deltaX是否滿足左滑的條件
*
*/
slide: function (handler) {
this.ele.addEventListener("touchstart", touchFn);
this.ele.addEventListener("touchend", touchFn);
var startX, startY, endX, endY;
function touchFn(e) {
e.preventDefault();
var firstTouch = e.changedTouches[0];
switch (e.type) {
case "touchstart":
startX = firstTouch.pageX;
startY = firstTouch.pageY;
break;
case "touchend":
endX = firstTouch.pageX;
endY = firstTouch.pageY;
//x方向移動大於y方向的移動,並且x方向的移動大於25個畫素,表示在向左側滑動
if (Math.abs(endX - startX) >= Math.abs(endY - startY) && startX - endX >= 25) {
handler.call(this, e, 'left');
}else if(Math.abs(endX - startX) >= Math.abs(endY - startY) && startX - endX < -25){
handler.call(this, e, 'right');
}else if(Math.abs(endX - startX) < Math.abs(endY - startY) && startY - endY >= 25){
handler.call(this, e, 'up');
}else if(Math.abs(endX - startX) < Math.abs(endY - startY) && startY - endY < -25){
handler.call(this, e, 'down');
}
break;
}
}
},
/**
* 右側滑動。
*
*/
slideRight: function (e) {
}
}
window.$$ = window.myQuery = myQuery;
})(window);
$$("div").tap(function (e) {
console.log("單擊事件")
})
$$("div").slide(function (e, type) {
let content = ''
console.log(this);
type === 'left' && (content = "左側滑動了.....");
type === 'right' && (content = "右側滑動了....");
type === 'up' && (content = "向上滑動了....");
type === 'down' && (content = "向下滑動了....");
this.innerHTML = content;
})
$$("div").longTag(function () {
console.log("長按事件");
})
var _x_start, _y_start, _x_move, _y_move, _x_end, _y_end, left_start, top_start;
document.getElementById("content").addEventListener("touchstart", function (e) {
_x_start = e.touches[0].pageX;
_y_start = e.touches[0].pageY;
left_start = $("#content").css("left");
top_start = $("#content").css("top");
})
document.getElementById("content").addEventListener("touchmove", function (e) {
_x_move = e.touches[0].pageX;
_y_move = e.touches[0].pageY;
$("#content").css("left", parseFloat(_x_move) - parseFloat(_x_start) + parseFloat(left_start) + "px");
$("#content").css("top", parseFloat(_y_move) - parseFloat(_y_start) + parseFloat(top_start) + "px");
})
document.getElementById("content").addEventListener("touchend", function (e) {
// var _x_end=e.changedTouches[0].pageX;
// var _y_end=e.changedTouches[0].pageY;
// console.log("end",_x_end)
})
//阻止瀏覽器下拉事件
$('body').on('touchmove', function (event) { event.preventDefault(); });
</script>
</html>
複製程式碼
是不是覺得可以很自由的操控一個元素了?哈哈哈。。。
接下來我們在看一個進度條的例子:
這裡有一點對range
的擴充套件,有興趣的可以瞭解一下,不看也不影響理解。--學習連結
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
.scroll {
top: 100px;
left: 100px;
position: relative;
width: 500px;
height: 5px;
background: rgb(180, 180, 180);
}
.bar {
position: absolute;
top: -3px;
height: 10px;
width: 8px;
background: rgb(255, 0, 0);
}
.mask {
position: absolute;
height: 5px;
background: rgb(255, 0, 0);
}
</style>
</head>
<body>
<div class="scroll">
<div class="bar"></div>
<div class="mask"></div>
</div>
<p></p>
</body>
<script>
// debugger
var bar = document.getElementsByClassName('bar')[0];
var scroll = document.getElementsByClassName('scroll')[0];
var bar = document.getElementsByClassName('bar')[0];
var mask = document.getElementsByClassName('mask')[0];
bar.onmousedown = function(e){
var leftVal = e.clientX - this.offsetLeft;
var that = this;
document.onmousemove = function(e){
barLeft = e.clientX - leftVal;
if(barLeft < 0){
barLeft = 0
}else if(barLeft > scroll.offsetWidth - bar.offsetWidth){
barLeft = scroll.offsetWidth - bar.offsetWidth;
}
bar.style.left = barLeft + 'px';
mask.style.width = barLeft + 'px';
document.getElementsByTagName('p')[0].innerHTML = '已經完成了' + Math.floor((barLeft / (scroll.offsetWidth - bar.offsetWidth))*100) + '%'
//防止拖動過快時滑鼠彈起後mousemove還在生效
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
}
}
document.onmouseup = function () {
document.onmousemove = null; //彈起滑鼠不做任何操作
}
</script>
</html>
複製程式碼
是不是感覺還挺實用的,哈哈哈!
好啦,今天先扯到這裡。
end。。。。。