实现一个简单的拖拽
- 拖拽的思路
- 拿到鼠标点击元素时,元素一开始的位置;
- 拿到鼠标移动的距离:鼠标移动实时的位置 - 鼠标点击的位置;
- 确定鼠标移动后,元素的位置:元素一开始的位置 + 鼠标移动的距离;
- 图解
- 示例代码(此时拖拽功能还是有瑕疵)
HTMLCSSJavaScript
<body> <div id="test"></div> </body>
* { margin: 0; padding: 0; } html, body { height: 100%; overflow: hidden; /*防止出现滚动条*/ } #test { position: absolute; left: 0; top: 0; width: 150px; height: 150px; background: pink; }
window.onload = function () { var testNode = document.querySelector("#test"); // 元素相对于视口的初始位置 var startPoint = { x: 0, y: 0 }; // 鼠标点击的初始位置 var mouseDownPoint = { x: 0, y: 0 } // 鼠标按下 testNode.onmousedown = function (ev) { ev = ev || event; startPoint.x = this.offsetLeft; startPoint.y = this.offsetTop; mouseDownPoint.x = ev.clientX; mouseDownPoint.y = ev.clientY; // 由于 onmousemove 可以单独触发,则放到鼠标点击事件中 // 鼠标移动过快不能触发移动事件,将事件绑定到 document 上面 document.onmousemove = function (ev) { ev = ev || event; // 实时鼠标移动 var mouseMovePoint = { x: 0, y: 0 } mouseMovePoint.x = ev.clientX; mouseMovePoint.y = ev.clientY; // 鼠标移动的距离 var dis = { x: 0, y: 0 }; dis.x = mouseMovePoint.x - mouseDownPoint.x; dis.y = mouseMovePoint.y - mouseDownPoint.y; testNode.style.left = startPoint.x + dis.x + "px"; testNode.style.top = startPoint.y + dis.y + "px"; } // 松掉鼠标:清除事件 document.onmouseup = function () { document.onmousemove = document.onmouseup = null; } } }
处理阻止默认事件
-
示例代码
HTMLCSSJavaScript<body> 这段文字被选中时,文字会被拖拽 <div id="test"></div> </body>
* { margin: 0; padding: 0; } html, body { height: 100%; overflow: hidden; } #test { position: absolute; left: 0; top: 0; width: 150px; height: 150px; background: pink; }
window.onload = function () { var testNode = document.querySelector("#test"); // 元素相对于视口的初始位置 var startPoint = { x: 0, y: 0 }; // 鼠标点击的初始位置 var mouseDownPoint = { x: 0, y: 0 } // 鼠标按下 testNode.onmousedown = function (ev) { ev = ev || event; startPoint.x = this.offsetLeft; startPoint.y = this.offsetTop; mouseDownPoint.x = ev.clientX; mouseDownPoint.y = ev.clientY; // 由于 onmousemove 可以单独触发,则放到鼠标点击事件中 // 鼠标移动过快不能触发移动事件,将事件绑定到 document 上面 document.onmousemove = function (ev) { ev = ev || event; // 实时鼠标移动 var mouseMovePoint = { x: 0, y: 0 } mouseMovePoint.x = ev.clientX; mouseMovePoint.y = ev.clientY; // 鼠标移动的距离 var dis = { x: 0, y: 0 }; dis.x = mouseMovePoint.x - mouseDownPoint.x; dis.y = mouseMovePoint.y - mouseDownPoint.y; testNode.style.left = startPoint.x + dis.x + "px"; testNode.style.top = startPoint.y + dis.y + "px"; } // 松掉鼠标:清除事件 document.onmouseup = function () { document.onmousemove = document.onmouseup = null; } // 阻止事件的默认行为,否则文字 会被拖拽 // IE8 以下的默认行为 不能阻止,使用全局捕获解决 return false; } }
-
效果展示(没有被阻止默认行为之前)
处理全局捕获兼容问题
-
全局捕获
- 在谷歌下:没有全局捕获;
- 在火狐下:全局捕获有定义,但没有实际的作用;
- 在 IE 下:全局捕获专治各种不服;
-
设置全局捕获
- element.setCapture;
- 在处理一个 mousedown 事件过程中调用这个方法来把全部的鼠标事件重新定向到这个元素,直到鼠标按钮被释放或者 document.releaseCapture() 被调用;
-
取消全局捕获
- document.releaseCapture;
- 如果该 document 中的一个元素之上当前启用了鼠标捕获,则释放鼠标捕获;
-
示例代码
HTMLCSSJavaScript<body> 文字拖拽已经被阻止 <div id="test"></div> </body>
* { margin: 0; padding: 0; } html, body { height: 100%; overflow: hidden; } #test { position: absolute; left: 0; top: 0; width: 150px; height: 150px; background: pink; }
window.onload = function () { var testNode = document.querySelector("#test"); // 元素相对于视口的初始位置 var startPoint = { x: 0, y: 0 }; // 鼠标点击的初始位置 var mouseDownPoint = { x: 0, y: 0 } testNode.onmousedown = function (ev) { ev = ev || event; startPoint.x = this.offsetLeft; startPoint.y = this.offsetTop; mouseDownPoint.x = ev.clientX; mouseDownPoint.y = ev.clientY; //曲线救国:不让焦点离开元素,间接的阻止了 document 的默认行为 if (this.setCapture) { this.setCapture(); } document.onmousemove = function (ev) { ev = ev || event; var mouseMovePoint = { x: 0, y: 0 } mouseMovePoint.x = ev.clientX; mouseMovePoint.y = ev.clientY; var dis = { x: 0, y: 0 }; dis.x = mouseMovePoint.x - mouseDownPoint.x; dis.y = mouseMovePoint.y - mouseDownPoint.y; testNode.style.left = startPoint.x + dis.x + "px"; testNode.style.top = startPoint.y + dis.y + "px"; } document.onmouseup = function () { document.onmousemove = document.onmouseup = null; if (document.releaseCapture) { document.releaseCapture(); } } // IE8 以下的默认行为 不能阻止,使用全局捕获解决 return false; } }
增加限制范围、磁性吸附
<body>
<div id="test"></div>
</body>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
#test {
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 150px;
background: pink;
}
window.onload = function () {
var testNode = document.querySelector("#test");
// 元素相对于视口的初始位置
var startPoint = { x: 0, y: 0 };
// 鼠标点击的初始位置
var mouseDownPoint = { x: 0, y: 0 }
testNode.onmousedown = function (ev) {
ev = ev || event;
startPoint.x = this.offsetLeft;
startPoint.y = this.offsetTop;
mouseDownPoint.x = ev.clientX;
mouseDownPoint.y = ev.clientY;
//曲线救国
if (this.setCapture) {
this.setCapture();
}
document.onmousemove = function (ev) {
ev = ev || event;
var mouseMovePoint = { x: 0, y: 0 }
mouseMovePoint.x = ev.clientX;
mouseMovePoint.y = ev.clientY;
var dis = { x: 0, y: 0 };
dis.x = mouseMovePoint.x - mouseDownPoint.x;
dis.y = mouseMovePoint.y - mouseDownPoint.y;
var L = startPoint.x + dis.x;
var T = startPoint.y + dis.y;
// // 限制左边界
// if (L < 0) {
// L = 0;
// }
// // 限制上边界
// if (T < 0) {
// T = 0;
// }
// // 限制下边界
// if (T > (document.documentElement.clientHeight - testNode.offsetHeight)) {
// T = (document.documentElement.clientHeight - testNode.offsetHeight)
// }
// // 限制右边界
// if (L > (document.documentElement.clientWidth - testNode.offsetWidth)) {
// L = (document.documentElement.clientWidth - testNode.offsetWidth)
// }
// 左边距 小于 10 ,设置为 0
if (L < 10) {
L = 0;
}
// 上边距 小于 10 ,设置为 0
if (T < 10) {
T = 0;
}
// 下边距 小于 10,设置为 0
if (T > (document.documentElement.clientHeight - testNode.offsetHeight - 10)) {
T = (document.documentElement.clientHeight - testNode.offsetHeight)
}
// 右边距 小于 10,设置为 0
if (L > (document.documentElement.clientWidth - testNode.offsetWidth - 10)) {
L = (document.documentElement.clientWidth - testNode.offsetWidth)
}
testNode.style.left = L + "px";
testNode.style.top = T + "px";
}
document.onmouseup = function () {
document.onmousemove = document.onmouseup = null;
if (document.releaseCapture) {
document.releaseCapture();
}
}
return false;
}
}
增加碰撞检测
-
图解:(根据视口中的元素距离视口的距离来判断)
-
示例代码
HTMLCSSJavaScript<body> <div id="test"></div> <img id="zaw" src="img/tg.png" /> </body>
* { margin: 0; padding: 0; } html, body { height: 100%; overflow: hidden; } #test { position: absolute; left: 0; top: 0; width: 200px; height: 200px; background: pink; } #zaw { position: absolute; left: 600px; top: 200px; width: 500px; height: 300px; }
window.onload = function () { var testNode = document.querySelector("#test"); var imgNode = document.querySelector("img"); // 元素相对于视口的初始位置 var startPoint = { x: 0, y: 0 }; // 鼠标点击的初始位置 var mouseDownPoint = { x: 0, y: 0 } testNode.onmousedown = function (ev) { ev = ev || event; startPoint.x = this.offsetLeft; startPoint.y = this.offsetTop; mouseDownPoint.x = ev.clientX; mouseDownPoint.y = ev.clientY; //曲线救国 if (this.setCapture) { this.setCapture(); } document.onmousemove = function (ev) { ev = ev || event; var mouseMovePoint = { x: 0, y: 0 } mouseMovePoint.x = ev.clientX; mouseMovePoint.y = ev.clientY; var dis = { x: 0, y: 0 }; dis.x = mouseMovePoint.x - mouseDownPoint.x; dis.y = mouseMovePoint.y - mouseDownPoint.y; var L = startPoint.x + dis.x; var T = startPoint.y + dis.y; //限制范围 磁性吸附 if (L < 10) { L = 0; } else if (L > (document.documentElement.clientWidth - testNode.offsetWidth - 10)) { L = (document.documentElement.clientWidth - testNode.offsetWidth) } if (T < 10) { T = 0; } else if (T > (document.documentElement.clientHeight - testNode.offsetHeight - 10)) { T = (document.documentElement.clientHeight - testNode.offsetHeight) } testNode.style.left = L + "px"; testNode.style.top = T + "px"; //碰撞检测 var T1 = testNode.offsetTop; var B1 = testNode.offsetTop + testNode.offsetHeight; var R1 = testNode.offsetLeft + testNode.offsetWidth var L1 = testNode.offsetLeft; var T2 = imgNode.offsetTop; var B2 = imgNode.offsetTop + imgNode.offsetHeight; var R2 = imgNode.offsetLeft + imgNode.offsetWidth var L2 = imgNode.offsetLeft; if (R1 < L2 || B1 < T2 || L1 > R2 || T1 > B2) { //没有撞到 imgNode.src = "img/tg.png"; } else { imgNode.src = "img/xfz.png"; } } document.onmouseup = function () { document.onmousemove = document.onmouseup = null; if (document.releaseCapture) { document.releaseCapture(); } } return false; } }
-
效果展示
拖拽(封装)
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
#test {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 200px;
background: pink;
}
#zaw {
position: absolute;
left: 600px;
top: 200px;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="test"></div>
<img id="zaw" src="img/tg.png" />
</body>
<script src="js/damu.js"></script>
<script type="text/javascript">
window.onload = function () {
var testNode = document.querySelector("#test");
var imgNode = document.querySelector("img");
damu.drag(testNode, true, 100, imgNode);
}
</script>
</html>
// damu.js
(function (w) {
w.damu = {};
/**
* @param {*} node 拖拽元素
* @param {*} flag flag:是否限制范围
* @param {*} value 吸附程度
* @param {*} node2 碰撞元素
*/
damu.drag = function (node, flag, value, node2) {
var limit = true;
var adsorption = 0;
var startPoint = { x: 0, y: 0 };
var mouseDownPoint = { x: 0, y: 0 }
node.onmousedown = function (ev) {
ev = ev || event;
startPoint.x = this.offsetLeft;
startPoint.y = this.offsetTop;
mouseDownPoint.x = ev.clientX;
mouseDownPoint.y = ev.clientY;
if (this.setCapture) {
this.setCapture();
}
document.onmousemove = function (ev) {
ev = ev || event;
var mouseMovePoint = { x: 0, y: 0 }
mouseMovePoint.x = ev.clientX;
mouseMovePoint.y = ev.clientY;
var dis = { x: 0, y: 0 };
dis.x = mouseMovePoint.x - mouseDownPoint.x;
dis.y = mouseMovePoint.y - mouseDownPoint.y;
var L = startPoint.x + dis.x;
var T = startPoint.y + dis.y;
// 限制范围
limit = flag === false ? false : true;
if (limit) {
// 吸附程度
if (value) {
adsorption = value;
}
if (L < adsorption) {
L = 0;
} else if (L > (document.documentElement.clientWidth - node.offsetWidth - adsorption)) {
L = (document.documentElement.clientWidth - node.offsetWidth)
}
if (T < adsorption) {
T = 0;
} else if (T > (document.documentElement.clientHeight - node.offsetHeight - adsorption)) {
T = (document.documentElement.clientHeight - node.offsetHeight)
}
}
node.style.left = L + "px";
node.style.top = T + "px";
// 碰撞检测
if (node2) {
var T1 = node.offsetTop;
var B1 = node.offsetTop + node.offsetHeight;
var R1 = node.offsetLeft + node.offsetWidth
var L1 = node.offsetLeft;
var T2 = node2.offsetTop;
var B2 = node2.offsetTop + node2.offsetHeight;
var R2 = node2.offsetLeft + node2.offsetWidth
var L2 = node2.offsetLeft;
if (R1 < L2 || B1 < T2 || L1 > R2 || T1 > B2) {
node2.src = "img/tg.png";
} else {
node2.src = "img/xfz.png";
}
}
}
document.onmouseup = function () {
document.onmousemove = document.onmouseup = null;
if (document.releaseCapture) {
document.releaseCapture();
}
}
return false;
}
}
})(window)
第 3️⃣ 座大山:DOM 事件
上一篇