拖拽

拖拽功能是H5里提供的一个标准。有了拖拽功能之后,为我们的网站提供了更多的交互选择。

拖拽的流程

  • 拖拽元素 drap
  • 释放元素 drop

源对象和目标对象

  • 源对象
    • 被拖拽的元素被称之为 源对象
  • 目标对象
    • 当拖拽的元素被放下或者划过某个元素的时候,该元素就是我们的目标对象

draggable

当你希望对某个元素进行拖拽的时候,需要为该元素设置draggable属性

链接和图像默认是可拖动的。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .app {
      width:200px;
      height: 200px;
    }
    #app1 {
      background-color: cyan;
    }
    #app2 {
      background-color: orange;
    }
  </style>
</head>
<body>
  <div id="app1"  class="app " draggable="true"></div>
  <div id="app2" class="app" ></div>
</body>
</html>

从上图中我们可以看出,设置了draggable的元素是可以被拖动的,而没有设置的元素则无法拖动

源对象的操作函数

  • ondragstart: 源对象开始被拖动时触发
  • ondrag: 源对象正在被拖动的过程中触发,会触发多次
  • ondragend: 源对象拖动结束(被放下后者取消)

例子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .app {
      width:200px;
      height: 200px;
    }
    #app1 {
      background-color: cyan;
      font-size: 28px;
    }
  </style>
</head>
<body>
  <div id="app1"  
    class="app" 
    draggable="true" 
    ondragstart="dragStart()"
    ondrag="draging()"
    ondragend="dragEnd()"
    >源对象</div>
</body>
</html>

<script>
  function dragStart(){
    console.log("开始拖拽");
  }
  function draging(){
    console.log("元素正在被拖拽");
  }
  function dragEnd(){
    console.log("拖拽结束");
  }
  </script>

目标对象相关方法

  • ondragenter: 源对象进入目标对象范围时触发
  • ondragover: 源对象在目标对象范围内拖拽时触发
  • ondragleave: 源对象被拖离目标对象范围时触发
  • ondrop: 源对象在目标对象范围内被释放的时候触发
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .app {
      width:100px;
      height: 100px;
    }
    #app1 {
      background-color: cyan;
      font-size: 28px;
    }

    #app2 {
      width: 200px;
      height: 200px;
      background-color: orange;
    }
  </style>
</head>
<body>
  <div id="app1"  
      class="app" 
      draggable="true" 
      >源对象</div>

  <div id="app2" 
    ondragenter="dragenter()"
    ondragover="dragover()"
    ondragleave="dragleave()"
    ondrop="drop()"
  ></div>
</body>
</html>

<script>
function dragenter(){
  console.log("拖拽的元素,进入到App2的范围内");
}
function dragover(){
  console.log("拖拽的元素在app2的元素内,飞来飞去");
}
function dragleave(){
  console.log("拖拽的元素离开了app2元素");
}
function drop(){
  console.log("拖拽的元素被放入到app2元素内");
}
</script>

在上面的例子中,我们在橙色的元素里放下蓝色的元素,但是在最终蓝色元素并没有停留在橙色区块中,而是回到原来的位置上。

dataTransfer

为了能够得到拖拽元素的相关信息,H5为每个相关的事件提供了dataTransfer对象,用于在源对象和目标对象的事件传递数据。

  • setData(key,value) 保存数据
  • getData(key) //获取数据

  • 取消目标元素的默认事件,否则无法放下元素

  • 在拖拽的开始就记录 源对象的相关信息,
  • 在目标元素上执行drop事件时,获取源对象的相关信息,并将该元素插入到目标元素上
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .app {
      width:100px;
      height: 100px;
    }
    #app1 {
      background-color: cyan;
      font-size: 28px;
    }

    #app2 {
      width: 200px;
      height: 200px;
      background-color: orange;
    }
  </style>
</head>
<body>
  <div id="app1"  
      class="app" 
      draggable="true" 
      ondragstart="dragStart(event)"
      >源对象</div>

  <div id="app2" 
    ondragover="dragover(event)"
    ondrop="drop(event)"
  ></div>
</body>
</html>

<script>

// 在滑动的过程中,取消目标元素的默认事件
function dragover(ev){
  ev.preventDefault();
}
// 释放元素
function drop(ev){
  // 取消元素的默认事件
  ev.preventDefault();
  //获取源对象的相关信息
  let sourceId = ev.dataTransfer.getData('sourceId');
  //获取源对象相关的元素,
  let sourceElement = document.getElementById(sourceId);
  //插入到目标元素中
  ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
    ev.dataTransfer.setData('sourceId',ev.target.id)
}

</script>

实例

  1. 左右两个元素列表互相拖拽

需求:

  1. 左右两列可以互相拖拽释放元素
  2. 在图片上面不能放下其他元素


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .container {
      width: auto;
      height: 400px;
      display: flex;
      flex-direction: row;
    }
    .app {
      width:200px;
      height: 400px;
    }
    .app li {
      width: 100%;
    }
    .app li img {
      width: 100%;
    }
    #app1 {
      background-color: cyan;
    }

    #app2 {
      background-color: orange;
      margin-left: 100px;
    }
  </style>
</head>
<body>
  <div class="container">
    <ul id="app1"  
      class="app" 
      ondragstart="dragStart(event)"
      ondragover="dragover(event)"
      ondrop="drop(event)"
      >
      <li  draggable="true" id="li1" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
      </li>
      <li  draggable="true" id="li2" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
      </li>
      <li  draggable="true" id="li3" ondragstart="dragStart(event)" ondrop="stopDrop(event)">
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
      </li>
  </ul>

  <ul id="app2"  class="app"
    ondragover="dragover(event)"
    ondrop="drop(event)"
  ></ul>
  </div>

</body>
</html>

<script>
function stopDrop(ev){
  ev.stopPropagation();
  return false;
}
// 在滑动的过程中,取消目标元素的默认事件
function dragover(ev){
  ev.preventDefault();
}
// 释放元素
function drop(ev){
  // 取消元素的默认事件
  ev.preventDefault();
  //获取源对象的相关信息
  let sourceId = ev.dataTransfer.getData('sourceId');
  //获取源对象相关的元素,
  let sourceElement = document.getElementById(sourceId);
  //插入到目标元素中
  ev.target.appendChild(sourceElement);
}
//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
  console.log("开始拖拽======",ev);
    ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}

</script>

在上面的例子中,我们使用了内联JS,看起来比较繁琐。因此,下面我们用内嵌JS的方式来处理

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .container {
      width: auto;
      height: 400px;
      display: flex;
      flex-direction: row;
    }
    .app {
      width:200px;
      height: 400px;
    }
    .app li {
      width: 100%;
    }
    .app li img {
      width: 100%;
    }
    #app1 {
      background-color: cyan;
    }

    #app2 {
      background-color: orange;
      margin-left: 100px;
    }
  </style>
</head>
<body>
  <div class="container">
    <ul id="app1"  
      class="app" 
      >
      <li  draggable="true" class="list" id="li1">
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
      </li>
      <li  draggable="true" class="list" id="li2"  >
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
      </li>
      <li  draggable="true" class="list" id="li3"  >
        <img ondrop="stopDrop(event)" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
      </li>
  </ul>

  <ul id="app2"  class="app"></ul>
  </div>

</body>
</html>

<script>

let apps = document.getElementsByClassName("app");
let lists = document.getElementsByClassName("list");

for(let i=0,length=apps.length;i<length;i++){
  let app = apps[i];
  // 在滑动的过程中,取消目标元素的默认事件,允许拖拽内容放下
  app.ondragover = function(ev){
    ev.preventDefault();
  }
  app.ondragstart = dragStart;
  app.ondrop = drop;
}

//设置所有lists元素开始拖拽
for(let i=0,length=lists.length;i<length;i++){
  let li = lists[i];
  li.ondragstart = dragStart;
  li.ondrop = stopDrop;
}

// 释放元素
function drop(ev){
  // 取消元素的默认事件
  ev.preventDefault();
  //获取源对象的相关信息
  let sourceId = ev.dataTransfer.getData('sourceId');
  //获取源对象相关的元素,
  let sourceElement = document.getElementById(sourceId);
  //插入到目标元素中
  ev.target.appendChild(sourceElement);
}

//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
  console.log("开始拖拽======",ev);
    ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}

function stopDrop(ev){
  ev.stopPropagation();
  return false;
}
</script>

在两个元素之间 插入新元素


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .container {
      width: auto;
      height: 400px;
      display: flex;
      flex-direction: row;
    }
    .app {
      width:200px;
      height: 400px;
    }
    .app li {
      width: 100%;
    }
    .app li img {
      width: 100%;
    }
    #app1 {
      background-color: cyan;
    }

    #app2 {
      background-color: orange;
      margin-left: 100px;
    }
  </style>
</head>
<body>
  <div class="container">
    <ul id="app1"  
      class="app" 
      >
      <li  draggable="true" class="list" id="li1">
        <img  src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620194&di=ce0f0e3feda2ed250b10c8d636010e86&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F4%2F56f62bab021a8.jpg" alt="">
      </li>
      <li  draggable="true" class="list" id="li2"  >
        <img  src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=abb8c8f648a493c832e25a20bd7937e2&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201204%2F13%2F161232b8vbsjjthbh0mty0.jpg" alt="">
      </li>
      <li  draggable="true" class="list" id="li3"  >
        <img  src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1596885620192&di=bbab3059864fa1ce42ff0b714184607f&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fblog%2F201510%2F14%2F20151014231057_r8tZm.jpeg" alt="">
      </li>
  </ul>

  <ul id="app2"  class="app"></ul>
  </div>

</body>
</html>

<script>

let apps = document.getElementsByClassName("app");
let lists = document.getElementsByClassName("list");

for(let i=0,length=apps.length;i<length;i++){
  let app = apps[i];
  // 在滑动的过程中,取消目标元素的默认事件,允许拖拽内容放下
  app.ondragover = function(ev){
    ev.preventDefault();

  }
  app.ondragstart = dragStart;
  app.ondrop = drop;
}

//设置所有lists元素开始拖拽
for(let i=0,length=lists.length;i<length;i++){
  let li = lists[i];
  li.ondragstart = dragStart;
  li.ondrop = dropLi;

}

// 释放元素
function drop(ev){
  // 取消元素的默认事件
  ev.preventDefault();
  //获取源对象的相关信息
  let sourceId = ev.dataTransfer.getData('sourceId');
  //获取源对象相关的元素,
  let sourceElement = document.getElementById(sourceId);
  //插入到目标元素中
  ev.target.appendChild(sourceElement);
}

//在开始拖拽元素时记录该元素相关信息
function dragStart(ev){
  ev.dataTransfer.setData('sourceId',ev.target.parentElement.id)
}

function dropLi(ev){
    ev.stopPropagation();
   //判断li元素放下的时候,目标元素是否是图片,查找该图片的父级元素
   let target = ev.target.parentElement;
   let parentEle = target.parentElement;

   //获取被拖拽的元素
   let dragId = ev.dataTransfer.getData("sourceId");
   let dragEle = document.getElementById(dragId);
   //计算 源对象 拖拽到 目标元素的位置,
   /*
    如果大于目标元素所在Y轴距离加上元素本身高度的一半,则将 源对象 放到目标元素的后面
    小于目标元素所在Y轴距离加上元素本身高度的一半,将 源对象放到目标元素的前面
   */
   //获取目标元素的位置
   let top = target.offsetTop;
   let clientHeight = target.clientHeight;

   //获取 鼠标放下的时候,源对象所在的Y轴位置
   let clientY = ev.clientY;
   let targetTop = top + top / 2;

    if(clientY > targetTop){
        //放在下面
        insertAfter(dragEle,target);
    }else{
        //放在上面
        console.log("放在上面",parentEle);
        parentEle.insertBefore(dragEle,target);
    }

   console.log("距离顶部的距离",top);
}

function stopDrop(ev){
  ev.stopPropagation();
  return false;
}
// 在后面插入元素
function insertAfter(newEl, targetEl) {
    var parentEl = targetEl.parentNode;
    if (parentEl.lastChild == targetEl) {
        parentEl.appendChild(newEl);
    } else {
        parentEl.insertBefore(newEl, targetEl.nextSibling);
    }
}
</script>

将外部文件拖入到页面中

<!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>

        #container {
            width: 300px;
            height: 300px;
            border: 1px dashed black;
        }
        .fileList{
            width: 100%;
            list-style: none;
        }
        .imgList {
            width: 100px;
        }
        .imgList img {
            width: 100%;
        }
    </style>
</head>
<body>
    <form id="container">
        <span>请将文件拖拽到这里</span>
        <ul class="fileList"></ul>
    </form>
</body>
</html>

<script>
    var container = document.getElementById('container');
    var fileList = document.querySelector(".fileList");
    container.addEventListener("dragenter",function(ev){
        var ev = ev || window.event;
        ev.preventDefault();
        ev.stopPropagation();
    })
    container.addEventListener("dragover",function(ev){
        var ev = ev || window.event;
        ev.preventDefault();
        ev.stopPropagation();
    });
    container.addEventListener("drop",function(ev){
        var ev = ev || window.event;
        // console.log(ev.dataTransfer);
        var files = ev.dataTransfer.files;
        console.log(files);
        // 阻止默认事件和冒泡事件,避免浏览器直接打开图片
        ev.preventDefault();
        ev.stopPropagation();
        for(var i=0,length=files.length;i<length;i++){
            var file = files[i];
            console.log(file);
            //将文件转换成dataURL
            var fileURL = window.URL.createObjectURL(file);
            fileList.innerHTML = `
                <li class="imgList">
                    <img src=${fileURL} alt=${file.name}> 
                    <span>${file.name}</span>   
                </li>
            `
        }
    })
</script>

results matching ""

    No results matching ""