使用移动设备的触摸事件模拟拖放事件

2023-12-26

前段时间,我在移动设备上的网络浏览器中进行拖放操作时遇到了困难。默认的 JavaScript 事件在移动设备上不起作用。您只能使用触摸事件。

就我而言,我需要通过拖放来交换两个图像以及 ID。这里有一个例子:

div{
  display:inline-block;
  border:1px solid #0b79d0;
}

div, img{
        width:120px;
        height:120px;
    }
<div id="1" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
    <img id="a" draggable="true" ondragstart="dragStart(event)" src="https://static.webshopapp.com/shops/073933/files/156288269/345x345x1/artibalta-white-tiger.jpg"/>
</div>

<div id="2" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
    <img id="b" draggable="true" ondragstart="dragStart(event)" src="https://yt3.ggpht.com/a-/AN66SAyfsmao4f1EEOqkBP2PgpSUcabPJXLZ1sLEnA=s288-mo-c-c0xffffffff-rj-k-no"/>
</div>

<div id="3" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
    <img id="c" draggable="true" ondragstart="dragStart(event)" src="https://kinderbilder.download/wp-content/uploads/2018/10/animals-for-dolphin-drawings-pencil-drawings-pinterest-verwandt-mit-delfine-zeichnen-100x100.jpg"/>
</div>

<script>
    function allowDrop(ev){
        ev.preventDefault();
    }

    function dragEnter(ev){
        var element = document.getElementById(ev.target.id);
        element.style.border = "dotted";
        element.style.borderColor = "#0b79d0";
    }

    function dragLeave(ev){
        var element = document.getElementById(ev.target.id);
        element.style.border = "1px solid #0b79d0";
    }

    function dragStart(ev){
        ev.dataTransfer.setData("src", ev.target.id);
        var number = ev.target.id.replace ( /[^\d.]/g, '' );
        ev.dataTransfer.setData("text/plain", number);
    }

    function drop(ev) {
        ev.preventDefault();
        var src = document.getElementById(ev.dataTransfer.getData("src"));

        var srcParent = src.parentNode;
        var tgt = ev.currentTarget.firstElementChild;
        ev.currentTarget.replaceChild(src, tgt);
        srcParent.appendChild(tgt);

        var number1 = srcParent.id.replace(/[^\d.]/g, '');
        var number2 = ev.currentTarget.id.replace(/[^\d.]/g, '');

        var element = document.getElementById(ev.target.id);
        element.style.border = "solid 1px #0b79d0";

        var number = ev.target.id.replace(/[^\d.]/g, '');
    }
</script>

因此dragStart事件存储信息,例如图像。然而,这样的操作对于触摸事件是不可能的。

现在我想知道,有没有办法在移动设备上做同样的事情,通过使用触摸事件来模仿拖动事件?


对于新人来说,目前还没有数据传输 https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer对于触摸事件(还?)。您可以执行与以下相同的功能DnD https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API还有一点工作。DnD只需简化数据传输过程并处理一些诸如检测dragenter之类的事情,但是您也可以对触摸进行相同的操作,只是您必须自己完成所有dragenter检测工作。

在触摸开始时,我将拖动元素的引用存储到变量中,这与 dataTransfer.setData() 类似,但这里添加的工作是通过复制一个新元素来跟随触摸事件来模拟拖放的感觉

  function dragTouchstart(e){
//global variable that store the touch/drag element
  imgId = e.target
    let image = document.createElement("img"); // Create a new element
  image.setAttribute("id", "image-float");


  // get the image from the stored reference
  image.src =imgId.src
  image.width = 100
  image.height = 100

  // position the image to the touch, can be improve to detect the position of touch inside the image
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';
  image.style.opacity = 0.5;


  document.body.appendChild(image);  
  }

在 touchmove 上,这纯粹是为了模拟您从中获得的拖动感觉dnd,获取在 touchstart 中创建的元素并使其跟随您的 touchmove。但我还添加了 touchenter 功能来检测dragenter

   function dragTouchmove(e) {
  // on touch move or dragging, we get the newly created image element
  let image = document.getElementById('image-float')
  // this will give us the dragging feeling of the element while actually it's a different element
  let left = e.touches[0].pageX;
  let top = e.touches[0].pageY;
  image.style.position = 'absolute'
  image.style.left = left + 'px';
  image.style.top = top + 'px';
  let touchX = e.touches[0].pageX
  let touchY = e.touches[0].pageY
  //apply touch enter fucntion inside touch move
  dragTouchenter(e,touchX,touchY)
  }

我的触摸输入功能

  function dragTouchenter(e,touchX,touchY){
  let one =document.getElementById('1')
  let two =document.getElementById('2')
  let three =document.getElementById('3')
  
  let id1 = one.getBoundingClientRect();
  let id2 = two.getBoundingClientRect();
  let id3 = three.getBoundingClientRect();
  
    // to detect the overlap of touchmove with dropzone
  var overlap1 = !(id1.right < touchX ||
    id1.left > touchX ||
    id1.bottom < touchY ||
    id1.top > touchY)
    
  var overlap2 = !(id2.right < touchX ||
    id2.left > touchX ||
    id2.bottom < touchY ||
    id2.top > touchY)
    
     var overlap3 = !(id3.right < touchX ||
    id3.left > touchX ||
    id3.bottom < touchY ||
    id3.top > touchY)
    
    //detect touchenter then apply style, if false, equal to touchleave
    //could write a better function to take these elements in array and apply function accordingly
    //but as for now I just write like this because faster by copy+paste
    //get dropZoneId too
    if(overlap1){
     one.style.border = "dotted";
    one.style.borderColor = "#0b79d0";
    dropZoneId =one
    }else{
    one.style.border = "1px solid #0b79d0";
    }
    
    if(overlap2){
     two.style.border = "dotted";
    two.style.borderColor = "#0b79d0";    
    dropZoneId =two
    }else{
    two.style.border = "1px solid #0b79d0";
    }
    
    if(overlap3){
     three.style.border = "dotted";
    three.style.borderColor = "#0b79d0";
    dropZoneId =three
    }else{
    three.style.border = "1px solid #0b79d0";
    }
    
    if(!overlap1 && !overlap2 && !overlap3){
    dropZoneId = ''
    }
    
    /* console.log(dropZoneId.id) */
  }

最后 ontouchend 将执行您将使用 dataTransfer.getData() 执行的所有逻辑

  function dragTouchend(e){
  //remove dragged image duplicate
    let image = document.getElementById('image-float')
    image.remove()
    
    dropZoneId.style.border = "1px solid #0b79d0";
    //if outside any dropzone, just do nothing
    if(dropZoneId == '') {
    dropZoneId = ''
    imgId = ''
    }else{
    // if inside dropzone, swap the image 
    let toSwap = dropZoneId.children[0]
    let originDropzone= imgId.parentElement
    originDropzone.appendChild(toSwap)
    dropZoneId.appendChild(imgId)
    
    dropZoneId = ''
    imgId = ''
    
    }
  }

基于 OP 的完整工作示例如下,更改了图像,因为它似乎已损坏

div {
  display: inline-block;
  border: 1px solid #0b79d0;
}

div,
img {
  width: 120px;
  height: 120px;
}
<div id="1" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
  <img id="a" draggable="true" ondragstart="dragStart(event)" src="https://static.webshopapp.com/shops/073933/files/156288269/345x345x1/artibalta-white-tiger.jpg" ontouchstart="dragTouchstart(event)" ontouchmove="dragTouchmove(event)" ontouchend="dragTouchend(event)"
  />
</div>

<div id="2" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
  <img id="b" draggable="true" ondragstart="dragStart(event)" src="https://yt3.ggpht.com/a-/AN66SAyfsmao4f1EEOqkBP2PgpSUcabPJXLZ1sLEnA=s288-mo-c-c0xffffffff-rj-k-no" ontouchstart="dragTouchstart(event)" ontouchmove="dragTouchmove(event)" ontouchend="dragTouchend(event)"
  />
</div>

<div id="3" ondragover="allowDrop(event)" ondrop="drop(event)" ondragenter="dragEnter(event)" ondragleave="dragLeave(event)" draggable="false">
  <img id="c" draggable="true" ondragstart="dragStart(event)" src="https://cdn.quasar.dev/img/avatar1.jpg" ontouchstart="dragTouchstart(event)" ontouchmove="dragTouchmove(event)" ontouchend="dragTouchend(event)" />
</div>

<script>
  var imgId = 'test'
  var dropZoneId = ''

  function allowDrop(ev) {
    ev.preventDefault();
  }

  function dragTouchstart(e) {
    imgId = e.target
    let image = document.createElement("img"); // Create a new element
    image.setAttribute("id", "image-float");


    // get the image from the stored reference
    image.src = imgId.src
    image.width = 100
    image.height = 100

    // position the image to the touch, can be improve to detect the position of touch inside the image
    let left = e.touches[0].pageX;
    let top = e.touches[0].pageY;
    image.style.position = 'absolute'
    image.style.left = left + 'px';
    image.style.top = top + 'px';
    image.style.opacity = 0.5;


    document.body.appendChild(image);
  }

  function dragTouchmove(e) {
    // on touch move or dragging, we get the newly created image element
    let image = document.getElementById('image-float')
    // this will give us the dragging feeling of the element while actually it's a different element
    let left = e.touches[0].pageX;
    let top = e.touches[0].pageY;
    image.style.position = 'absolute'
    image.style.left = left + 'px';
    image.style.top = top + 'px';
    let touchX = e.touches[0].pageX
    let touchY = e.touches[0].pageY
    //apply touch enter fucntion inside touch move
    dragTouchenter(e, touchX, touchY)
  }

  function dragTouchenter(e, touchX, touchY) {
    let one = document.getElementById('1')
    let two = document.getElementById('2')
    let three = document.getElementById('3')

    let id1 = one.getBoundingClientRect();
    let id2 = two.getBoundingClientRect();
    let id3 = three.getBoundingClientRect();

    // to detect the overlap of touchmove with dropzone
    var overlap1 = !(id1.right < touchX ||
      id1.left > touchX ||
      id1.bottom < touchY ||
      id1.top > touchY)

    var overlap2 = !(id2.right < touchX ||
      id2.left > touchX ||
      id2.bottom < touchY ||
      id2.top > touchY)

    var overlap3 = !(id3.right < touchX ||
      id3.left > touchX ||
      id3.bottom < touchY ||
      id3.top > touchY)

    //detect touchenter then apply style, if false, equal to touchleave
    //could write a better function to take these elements in array and apply function accordingly
    //but as for now I just write like this because faster by copy+paste
    //get dropZoneId too
    if (overlap1) {
      one.style.border = "dotted";
      one.style.borderColor = "#0b79d0";
      dropZoneId = one
    } else {
      one.style.border = "1px solid #0b79d0";
    }

    if (overlap2) {
      two.style.border = "dotted";
      two.style.borderColor = "#0b79d0";
      dropZoneId = two
    } else {
      two.style.border = "1px solid #0b79d0";
    }

    if (overlap3) {
      three.style.border = "dotted";
      three.style.borderColor = "#0b79d0";
      dropZoneId = three
    } else {
      three.style.border = "1px solid #0b79d0";
    }

    if (!overlap1 && !overlap2 && !overlap3) {
      dropZoneId = ''
    }

    /* console.log(dropZoneId.id) */
  }

  function dragTouchend(e) {
    //remove dragged image duplicate
    let image = document.getElementById('image-float')
    image.remove()

    dropZoneId.style.border = "1px solid #0b79d0";
    //if outside any dropzone, just do nothing
    if (dropZoneId == '') {
      dropZoneId = ''
      imgId = ''
    } else {
      // if inside dropzone, swap the image 
      let toSwap = dropZoneId.children[0]
      let originDropzone = imgId.parentElement
      originDropzone.appendChild(toSwap)
      dropZoneId.appendChild(imgId)

      dropZoneId = ''
      imgId = ''

    }
  }

  function dragEnter(ev) {
    var element = document.getElementById(ev.target.id);
    element.style.border = "dotted";
    element.style.borderColor = "#0b79d0";
  }

  function dragLeave(ev) {
    var element = document.getElementById(ev.target.id);
    element.style.border = "1px solid #0b79d0";
  }

  function dragStart(ev) {
    ev.dataTransfer.setData("src", ev.target.id);
    var number = ev.target.id.replace(/[^\d.]/g, '');
    ev.dataTransfer.setData("text/plain", number);
  }

  function drop(ev) {
    ev.preventDefault();
    var src = document.getElementById(ev.dataTransfer.getData("src"));

    var srcParent = src.parentNode;
    var tgt = ev.currentTarget.firstElementChild;
    ev.currentTarget.replaceChild(src, tgt);
    srcParent.appendChild(tgt);

    var number1 = srcParent.id.replace(/[^\d.]/g, '');
    var number2 = ev.currentTarget.id.replace(/[^\d.]/g, '');

    var element = document.getElementById(ev.target.id);
    element.style.border = "solid 1px #0b79d0";

    var number = ev.target.id.replace(/[^\d.]/g, '');
  }
</script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用移动设备的触摸事件模拟拖放事件 的相关文章

随机推荐

  • 使用“AJAX”下载 CSV 文件

    我正在尝试为我的网站完成一项相当简单的任务 但我不确定具体如何去做 我希望用户查看一个表格 然后单击一个按钮 此时用户可以保存该表格该表的内容作为 csv 文件 此请求有时可能非常复杂 因此我生成一个进度页面来提醒用户 除了实际生成 csv
  • 使用 BeautifulSoup 选择所有 div 兄弟姐妹

    我有一个 html 文件 其结构如下 div div div div div div div div div div div div div div 我想选择所有兄弟 div 而不选择第三个和第四个块中的嵌套 div 如果我使用find a
  • 竞争条件:整数的最小和最大范围

    我最近在一次采访中被问到这个问题 给定以下代码 静态整数的最小和最大可能值是多少num import java util ArrayList import java util List public class ThreadTest pri
  • 统一选择将物品分布放入垃圾箱中

    想象一下你有n物品和m垃圾箱 所有物品都是相同的 但箱子是不同的 随机选择一批物品放入垃圾箱的最快算法是什么 例如 想象一下104是将 5 件物品放入 3 个箱子中 将 5 件物品放入 3 个箱子中 有 21 种可能的放置方式 005 01
  • 检查最近x秒内是否添加了mySQL记录

    我有一个 mySQL 数据库和一个表 在其中创建项目的新记录 创建的每个项目都有一个 项目名称 和一个事件创建日期 DATETIME 类型 可以有两个使用相同名称创建的项目 但是如果它们是由同一用户快速连续创建的 则可以安全地假设这是用户的
  • 如何将 Cucumber 测试结果保存到文件

    我有一些可以从控制台运行的黄瓜测试 rake cucumber 是否有命令行选项可以将测试结果存储到文本文件中 Either Run cucumber直接并使用 o From cucumber help o out FILE DIR Wri
  • 使用Python解析XML文件以获取所需数据并将其存储在mongodb数据库中

    我有一个 XML 文件 如下所示 我想从此文件中获取所有事件的以下信息 在类别事件下 开始日期 end date title 根据类别场地 address 地址2 city latitude 经度 name 邮政编码 然后将这些信息存储在
  • HeadersTooLargeException - 响应标头

    我在 Spring mvc 的项目中实现了文件下载 在下载文件时 它在 tomcat 7 服务器上出现以下错误 org apache coyote http11 HeadersTooLargeException An attempt was
  • Google Push-To-Deploy Pipelines - 单元测试因模块导入错误而失败

    当我尝试在 Compute Engine 中的 Google 配置的 Jenkins 服务器上执行构建时 出现以下错误 deployment 5371449468518400 1411607125060 bin sh xe tmp huds
  • 用于测试的 MQTT 代理

    尝试创建一个订阅 MQTT 代理并处理数据的 Python 脚本 然而 MQTT 代理到目前为止还没有收到任何数据 这使得测试变得困难 我发现以下脚本可以订阅主题并打印出有效负载 但我似乎无法连接到测试代理 import paho mqtt
  • ScrollViewer/StackPanel 构造内的 DataBound ListBox 和 Button,其中 Button 出现在 ListBox 内容末尾的下方

    我有以下构造 它显示了 StackPanel 内的 DataBound ListBox 和 Button 后者再次放置在 ScrollViewer 内
  • 从 mysqldump 创建的 SQL 恢复后出现错误 1465“无法在系统表上创建触发器”

    我在 amazon RDS 上运行 mysql 5 6 服务器 并设置一个只读副本 用于使用 mysqldump 创建备份 我尝试使用 all databases 选项 但是当我尝试导入 mysqldump 创建的 SQL 时 我最终从 m
  • 更新 Symfony2 上的composer.phar

    我有一个已经启动的 Symfony2 项目 我需要安装一个新捆绑 https packagist org packages doctrine mongodb odm bundle 正如我所见 我需要向我的composer json 添加一个
  • MySQLdb:操作数应包含 1 列

    我正在尝试使用 Python 和 MySQLdb 将一些数据插入 MySQL 数据库 当我在程序中执行以下函数时 MySQL 返回错误 1241 操作数应包含 1 列 用户 密码和数据库正确 表存在并且所有权限均已授予 def write
  • Pygame:无限滚动相机?

    所以我在 pygame 中编写了一个小型平台游戏 您可以在其中放置块并在它们上跳跃 但是 游戏仅限于窗口的边框 显然 那么如何添加使用 A 和 D 键滚动 相机 的方法呢 这是游戏的代码 import pygame random from
  • 在 Linq To Entities 中使用多个列连接表

    Linq to Entities 中的每个连接示例仅涉及on条款 如果我需要 2 列或更多列来制作 语法是什么join工作 如果可能的话 我还需要一个 Linq to Entities 查询表达式和基于方法的示例 下面是我需要的示例 表 1
  • PHP搜索引擎脚本

  • 哪些工具执行 IL 的编译后修改?

    最近提到 PostSharp 让我想起了这一点 去年我工作的时候 我们正在考虑使用 PostSharp 将检测注入到我们的代码中 这是在 Team Foundation Server 团队构建 持续集成环境中 考虑到这一点 我对 PostS
  • 帮助理解 javascript 全局消除技术

    来自 DailyJS 让我们构建一个 JavaScript 框架 http dailyjs com 2010 02 25 djscript part 1 structure 我不太确定以下代码 显然用作全局抑制技术 到目前为止 我的理解对
  • 使用移动设备的触摸事件模拟拖放事件

    前段时间 我在移动设备上的网络浏览器中进行拖放操作时遇到了困难 默认的 JavaScript 事件在移动设备上不起作用 您只能使用触摸事件 就我而言 我需要通过拖放来交换两个图像以及 ID 这里有一个例子 div display inlin