雪花台湾

彻底搞懂拖拽——基于滑鼠事件的拖拽以及基于HTML5 API的拖拽完整实现

一、基于滑鼠事件的拖拽

原理——onmousedown、onmousemove、onmouseup

  1. onmousedown

<a>, <address>, <area>, <b>, <bdo>, <big>, <blockquote>, <body>, <button>, <caption>, <cite>, <code>, <dd>, <dfn>, <div>, <dl>, <dt>, <em>, <fieldset>, <form>, <h1> to <h6>, <hr>, <i>, <img>, <input>, <kbd>, <label>, <legend>, <li>, <map>, <ol>, <p>, <pre>, <samp>, <select>, <small>, <span>, <strong>, <sub>, <sup>, <table>, <tbody>, <td>, <textarea>, <tfoot>, <th>, <thead>, <tr>, <tt>, <ul>, <var>

  1. onmousemove

<a>, <address>, <area>, <b>, <bdo>, <big>, <blockquote>, <body>, <button>, <caption>, <cite>, <code>, <dd>, <dfn>, <div>, <dl>, <dt>, <em>, <fieldset>, <form>, <h1> to <h6>, <hr>, <i>, <img>, <input>, <kbd>, <label>, <legend>, <li>, <map>, <ol>, <p>, <pre>, <samp>, <select>, <small>, <span>, <strong>, <sub>, <sup>, <table>, <tbody>, <td>, <textarea>, <tfoot>, <th>, <thead>, <tr>, <tt>, <ul>, <var>

  1. onmouseup

html <a>, <address>, <area>, <b>, <bdo>, <big>, <blockquote>, <body>, <button>, <caption>, <cite>, <code>, <dd>, <dfn>, <div>, <dl>, <dt>, <em>, <fieldset>, <form>, <h1> to <h6>, <hr>, <i>, <img>, <input>, <kbd>, <label>, <legend>, <li>, <map>, <ol>, <p>, <pre>, <samp>, <select>, <small>, <span>, <strong>, <sub>, <sup>, <table>, <tbody>, <td>, <textarea>, <tfoot>, <th>, <thead>, <tr>, <tt>, <ul>, <var>

具体实现

code:

<!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>
#test {
width: 100px;
height: 100px;
background: #000;
position: absolute;
color: #fff;
}
</style>
</head>

<body>
<div id="test">4616125</div>
<script>
(function() {
function Code() {}
Code.prototype = {
addEvent: function() {
var that = this;
var oDiv = document.getElementById(test);
oDiv.onmousedown = function(ev) {
var ev = ev || event;
var distanceX = ev.clientX - this.offsetLeft;
var distanceY = ev.clientY - this.offsetTop;
if (oDiv.setCapture) {
oDiv.setCapture();
}
document.onmousemove = function(ev) {
var ev = ev || event;
oDiv.style.left = ev.clientX - distanceX + px;
oDiv.style.top = ev.clientY - distanceY + px;
};
document.onmouseup = function(ev) {
document.onmousemove = document.onmouseup = null;
if (oDiv.releaseCapture) {
oDiv.releaseCapture();
}
};
};
},

init: function() {
var that = this;
window.onload = that.addEvent;
},
}
new Code().init();
})();
</script>
</body>

</html>

注意事项以及存在的问题:

  1. 注意事项
  • 存在的问题
  • 解决方案

    只需要实时计算拖拽的元素边框距离上下左右屏幕之间的距离就行了,具体代码如下:

    code:

    <!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>
    * {
    margin: 0;
    padding: 0;
    }
    #oDiv {
    width: 100px;
    height: 100px;
    background-color: #000;
    position: absolute;
    }
    </style>
    </head>

    <body>
    55555555555
    <div id="oDiv"></div>
    <script>
    oDiv.onmousedown = function(e) {
    var ev = e || event;
    var left = ev.clientX - oDiv.offsetLeft,
    top = ev.clientY - oDiv.offsetTop;
    document.onmousemove = function(e) {
    var ev = e || event;
    var leftW = ev.clientX - left;
    var topH = ev.clientY - top;
    //左边不能超出
    if (leftW < 0) {
    leftW = 0;
    }
    //上边不能超出
    if (topH < 0) {
    topH = 0;
    }
    //右边不能超出
    if (leftW > document.documentElement.clientWidth - oDiv.offsetWidth) {
    leftW = document.documentElement.clientWidth - oDiv.offsetWidth;
    }
    //下边不能超出
    if (topH > document.documentElement.clientHeight - oDiv.offsetHeight) {
    topH = document.documentElement.clientHeight - oDiv.offsetHeight;
    }
    oDiv.style.left = leftW + px;
    oDiv.style.top = topH + px;
    }
    document.onmouseup = function(e) {
    document.onmousemove = null;
    document.onmouseup = null;
    }
    return false;
    }
    </script>
    </body>

    </html>

    result:

    至此使用滑鼠事件的拖拽大功告成!

    二、基于HTML5拖拽API的拖拽

    前序知识介绍

    一个典型的拖拽操作是这样的:用户用滑鼠选中一个可拖动的(draggable)元素,移动滑鼠到一个可放置的(droppable)元素,然后释放滑鼠。 在操作期间,会触发一些事件类型,有一些事件类型可能会被多次触发(比如drag 和 dragover 事件类型)。

    这里涉及几个知识点:

    ps:图片来源(CAN I USE?)

    具体实现代码

    code:

    <!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">
    #thatDiv {
    width: 500px;
    height: 100px;
    border: 1px solid red;
    position: relative;
    }
    #thisDiv {
    width: 500px;
    height: 100px;
    border: 1px solid black;
    margin-bottom: 20px;
    }
    #tarDiv,
    #tarDiv1,
    #tarDiv2,
    #tarDiv3,
    #tarDiv4 {
    float: left;
    width: 50px;
    height: 50px;
    background-color: #000;
    border: 1px #fff solid;
    }
    .tarDiv {
    color: #fff;
    text-align: center;
    line-height: 50px;
    }
    </style>
    </head>

    <body>
    <div id="thisDiv">
    <div id="tarDiv" class="tarDiv" draggable="true">1</div>
    <div id="tarDiv1" class="tarDiv" draggable="true">2</div>
    <div id="tarDiv2" class="tarDiv" draggable="true">3</div>
    <div id="tarDiv3" class="tarDiv" draggable="true">4</div>
    <div id="tarDiv4" class="tarDiv" draggable="true">5</div>
    </div>
    <div id="thatDiv"></div>

    <script type="text/javascript">
    var tarDiv = document.getElementsByClassName("tarDiv");
    var thisDiv = document.getElementById("thisDiv");
    var thatDiv = document.getElementById("thatDiv");
    thisDiv.ondragstart = function(ev) {
    var ev = ev || window.event;
    ev.dataTransfer.setData("text", ev.target.id); //将被拖拽的元素的id存入dataTransfer对象中
    window.thisId = ev.target.id;
    ev.dataTransfer.effectAllowed = "copy";
    }
    thatDiv.ondragover = function(ev) { //阻止dragover的默认事件
    var ev = ev || window.event;
    if (typeof ev.preventDefault == "function") {
    ev.preventDefault();
    } else {
    ev.returnValue = false;
    }
    var div = document.getElementById(window.thisId);
    thatDiv.appendChild(div);
    div.style.cssText = "border:1px #fff dashed;";

    ev.preventDefault();
    ev.dataTransfer.dropEffect = "copy";
    }
    thatDiv.ondragenter = function(ev) { //阻止dragenter的默认事件
    var ev = ev || window.event;
    if (typeof ev.preventDefault == "function") {
    ev.preventDefault();
    } else {
    ev.returnValue = false;
    }
    }
    thatDiv.ondragleave = function(ev) {
    var ev = ev || window.event;
    var removeDiv = document.getElementById(window.thisId);
    thatDiv.removeChild(removeDiv);
    thisDiv.appendChild(removeDiv);
    removeDiv.style.cssText = "border:1px #fff solid;";
    ev.preventDefault();
    }
    thatDiv.ondrop = function(ev) {
    var ev = ev || window.event;
    var divId = ev.dataTransfer.getData("Text"); //从dataTransfer对象中取出数据
    if (typeof ev.preventDefault == "function") { //阻止drop事件的默认行为
    ev.preventDefault();
    } else {
    ev.returnValue = false;
    }
    var moveDiv = document.getElementById(divId);
    thatDiv.appendChild(moveDiv);
    moveDiv.setAttribute(draggable, false);
    moveDiv.style.cssText = "border:1px #fff solid;";

    }
    </script>
    </body>

    </html>

    result:

    os:这知乎的Markdown支持度让人难受!

    参考资料

    推荐阅读:

    相关文章