在可拖动元素上模拟 3 像素拖动 [英] simulate a 3 pixel drag on draggable elem

查看:24
本文介绍了在可拖动元素上模拟 3 像素拖动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是想模拟一个小的点击并拖动一个可拖动的div元素——我在这里发现了几个类似的问题,但都涉及使用额外的插件......

是否有简单的 JavaScript 或 jQuery 能力来专门处理拖动?据我所知 .click(); 或鼠标按下可以被调用来启动.

我不是想创造拖放的能力,我已经有了.我正在尝试创建一个自动模拟此事件的小函数.点击 > 按住 > 向上拖动 3 像素

<小时>

更新:在不使用第三方库的情况下无法在 SO 或其他地方找到任何关于此的信息,因此对其进行 500 悬赏.当然有可能.

解决方案

您可以使用 MouseEvent 界面和使用 DragEvent 接口.您必须使用 EventTarget.dispatchEvent().

我猜你结合了"HTML Drag and Drop API" 使用 "鼠标事件" 创建拖放行为,所以我会提供一个来模拟 Drag &Drop 和一个模拟鼠标捕获和鼠标移动.

模拟鼠标捕捉和鼠标移动

请阅读内嵌评论

//我们使用 MouseEvent 接口创建 3 个鼠标事件,//一个用于 mousedown 启动过程,//一个用于 mousemove 来处理移动//一个用于 mouseup 来终止进程const mouseDownEvent = new MouseEvent('mousedown', {clientX: element.getBoundingClientRect().left,clientY: element.getBoundingClientRect().top,气泡:真实,可取消:真});const mouseMoveEvent = new MouseEvent('mousemove', {clientX: element.getBoundingClientRect().left + 3,clientY: element.getBoundingClientRect().top,气泡:真实,可取消:真});const mouseUpEvent = new MouseEvent('mouseup', {气泡:真实,可取消:真});//将 mousedown 事件分派给具有监听器的元素element.dispatchEvent(mouseDownEvent);//对于mousemove,监听器可能是父级甚至是文档<元素|文档>.dispatchEvent(mouseMoveEvent);//调度 mouseup 终止进程element.dispatchEvent(mouseUpEvent);

运行代码片段.方形 div 元素是可拖动的,您可以在模拟计时器未运行时单击并拖动它.单击模拟按钮以查看正在运行的模拟:

//定时器 ID 持有者让 linearSimulationTimer;//模拟 X/Y 计算让 calcX = 0, calcY = 0;//模拟 X/Y 轴方向来处理父碰撞让 xAxisOrientation = 1, yAxisOrientation = 1;//X/Y 轴移动元素的像素数const pixelShift = 3;//元素const模拟按钮 = document.getElementById('simulate-dnm');constmovable = document.getElementById('movable');常量可移动容器 = 可移动的父节点;模拟Button.addEventListener('click', function() {//如果有定时器在运行如果(线性模拟定时器){//停止并清除定时器clearInterval(linearSimulationTimer);linearSimulationTimer = null;//创建一个没有自定义属性的简单 mouseup 事件const mouseUpEvent = new MouseEvent('mouseup', {气泡:真实,可取消:真,});//分派给可移动元素可移动.dispatchEvent(mouseUpEvent);//处理按钮标签文本(开始/停止)模拟按钮.classList.remove('运行');//否则如果没有计时器运行} 别的 {//使用可移动元素 client left/top 为 event clientX.clientY 创建 mousedown 事件const mouseDownEvent = new MouseEvent('mousedown', {clientX:movable.getBoundingClientRect().left,客户端:movable.getBoundingClientRect().top,第X页:0,第Y页:0,气泡:真实,可取消:真,视图:窗口});//将 mousedown 事件分派给可移动元素movable.dispatchEvent(mouseDownEvent);//获取可移动的父客户端矩形const parentRect =movable.parentNode.getBoundingClientRect();//启动模拟定时器linearSimulationTimer = setInterval(() => {//获取可移动元素的大小const { 宽度,高度 } = 可移动.getBoundingClientRect();//计算新的 X/Y 位置和方向calcX += pixelShift * xAxisOrientation;calcY += pixelShift * yAxisOrientation;//如果我们碰到可移动的父 X 轴边界,则反转 X 轴if (calcX + width > parentRect.width) {calcX = parentRect.width - 宽度;xAxisOrientation = -xAxisOrientation;} else if (calcX <0) {计算 X = 0;xAxisOrientation = -xAxisOrientation;}//如果我们碰到可移动的父 Y 轴边界,则反转 Y 轴if (calcY + height > parentRect.height) {calcY = parentRect.height - 高度;yAxisOrientation = -yAxisOrientation;} else if (calcY <0) {计算Y = 0;yAxisOrientation = -yAxisOrientation;}//使用 calcX/calcY 和父客户端位置创建 mousemove 事件const mouseMoveEvent = new MouseEvent('mousemove', {clientX: parentRect.left + calcX,clientY: parentRect.top + calcY,第X页:0,第Y页:0,气泡:真实,可取消:真,视图:窗口});//将 mousemove 事件分派给它具有侦听器的父级movableContainer.dispatchEvent(mouseMoveEvent);}, 50);//处理按钮标签文本(开始/停止)模拟按钮.classList.add('运行');}});//鼠标捕获和拖动处理程序 (https://javascript.info/mouse-drag-and-drop)movable.onmousedown = 函数(事件){让 shiftX = event.clientX -movable.getBoundingClientRect().left;让 shiftY = event.clientY -movable.getBoundingClientRect().top;moveAt(event.pageX, event.pageY);函数 moveAt(pageX, pageY) {movable.style.left = pageX - shiftX -movableContainer.offsetLeft + 'px';movable.style.top = pageY - shiftY -movableContainer.offsetTop + 'px';}功能 onMouseMove(事件){moveAt(event.pageX, event.pageY);}movableContainer.addEventListener('mousemove', onMouseMove);可移动.onmouseup = 函数(){movableContainer.removeEventListener('mousemove', onMouseMove);可移动.onmouseup = null;}}可移动.ondragstart = 函数(){返回假;}

#movable-container {位置:相对;高度:80px;宽度:200px;保证金:自动;底边距:20px;边框:1px点银;}#可移动{位置:相对;左:0;宽度:30px;高度:30px;背景颜色:矢车菊蓝;边框半径:5px;边框:1px 纯灰色;}#simulate-dnm >跨度:之前{内容:'开始';}#simulate-dnm.running >跨度:之前{内容:'停止';}

<div id="可移动"></div>

<div><button id="simulate-dnm"><span>鼠标捕捉&移动模拟</span></button>

模拟拖放

请阅读内嵌评论

//我们使用 DragEvent 接口创建了 3 个拖动事件,//一个用于 dragstart 启动进程,//一个用于 drop 处理拖放容器内的拖拽元素//和一个用于 dragend 终止进程const dragStartEvent = new DragEvent('dragstart', {气泡:真实,可取消:真});const dragEndEvent = new DragEvent('dragend', {气泡:真实,可取消:真});const dropEvent = new DragEvent('drop', {气泡:真实,可取消:真});//分派dr​​agstart事件给源元素发起sourceNode.dispatchEvent(dragStartEvent);//将放置事件分派到目标元素以获取拖动destinationNode.dispatchEvent(dropEvent);//将dragend事件分派给源元素完成sourceNode.dispatchEvent(dragEndEvent);

运行代码片段并点击模拟按钮以触发拖放事件序列:

//拖动元素所在的当前父索引让 currentParentIndex = 0;//元素constsimulateButton = document.getElementById('simulate-dnd');const sourceNode = document.getElementById('drag');函数模拟拖放(源节点,目标节点){//创建拖动开始事件const dragStartEvent = new DragEvent('dragstart', {气泡:真实,可取消:真});//创建拖拽事件const dragEndEvent = new DragEvent('dragend', {气泡:真实,可取消:真});//创建放置事件const dropEvent = new DragEvent('drop', {气泡:真实,可取消:真});//将dragstart 事件分派到可拖动元素sourceNode.dispatchEvent(dragStartEvent);//将放置事件发送到我们想要放置可拖动对象的容器元素destinationNode.dispatchEvent(dropEvent);//将dragend 事件分派到可拖动元素sourceNode.dispatchEvent(dragEndEvent);}模拟Button.addEventListener('click', function() {//将放置容器索引更改为当前容器以外的其他容器const newParentIndex = currentParentIndex === 0 ?1:0;//获取放置容器元素const destinationNode = document.getElementsByClassName('dropzone')[newParentIndex];//启动模拟序列模拟拖放(源节点,目标节点);//保存新的容器索引currentParentIndex = newParentIndex;});//拖放处理让拖;document.addEventListener("dragstart", function(event) {//存储一个引用.在被拖拽的元素上拖动 = event.target;//让它半透明event.target.style.opacity = .5;}, 错误的);document.addEventListener("dragend", function(event) {//重置透明度event.target.style.opacity = "";}, 错误的);/* 在放置目标上触发的事件 */document.addEventListener("dragover", function(event) {//防止默认允许丢弃event.preventDefault();}, 错误的);document.addEventListener("dragenter", function(event) {//当可拖动元素进入时突出显示潜在的放置目标if (event.target.className == "dropzone") {event.target.style.background = "黄色";}}, 错误的);document.addEventListener("dragleave", function(event) {//当可拖动元素离开时重置潜在放置目标的背景if (event.target.className == "dropzone") {event.target.style.background = "";}}, 错误的);document.addEventListener("drop", function(event) {//防止默认操作(作为某些元素的链接打开)event.preventDefault();//将拖动的元素移动到选定的放置目标if (event.target.className == "dropzone") {event.target.style.background = "";dragged.parentNode.removeChild(dragged);event.target.appendChild(拖动);currentParentIndex = Array.prototype.indexOf.call(event.target.parentNode.children, event.target);}}, false);

.dropzones {显示:弹性;justify-content:空间均匀;}.拖放区 {宽度:100px;高度:100px;背景颜色:薄荷糖;边框半径:5px;边框:2px 虚线深灰色;显示:弹性;对齐内容:居中;对齐项目:居中;底边距:10px;}#拖 {边距:未设置;宽度:40px;高度:40px;背景色:珊瑚色;边框半径:4px;边框:1px 纯灰色;}

<div class="dropzone"><div id="drag" draggable="true"></div>

<div class="dropzone"></div>

<div><button id="simulate-dnd">模拟拖拽&放下

I am simply trying to simulate a small click and drag on a draggable div elem — I've found several similar questions here on SO but all involving the use of additional plugins...

Is there a plain JavaScript or jQuery ability to handle specifically the drag? as I know .click(); or mouse down can be called to initiate.

I am not trying to create the ability of a drag and drop, I already have that. I am trying to create a small function that simulates this event automatically. click > hold > drag up 3 pixels


Update: Cannot find anything about this on SO or elsewhere without using a third party library, so creating a 500 bounty on it. Surely it's possible.

解决方案

You can simulate mouse events using MouseEvent interface and drag events using the DragEvent interface. You have to trigger the right sequence using EventTarget.dispatchEvent().

I guess that you combine "HTML Drag and Drop API" with "Mouse events" to create a drag and drop behaviour, so I'll provide one to simulate Drag & Drop and one to simulate Mouse capture and Mouse move.

Simulating Mouse capture and Mouse move

Please read inline comments

// We create 3 mouse events using MouseEvent interface,
// one for mousedown to initiate the process,
// one for mousemove to handle to movement
// and one for mouseup to terminate the process

const mouseDownEvent = new MouseEvent('mousedown', {
  clientX: element.getBoundingClientRect().left,
  clientY: element.getBoundingClientRect().top,
  bubbles: true,
  cancelable: true
});

const mouseMoveEvent = new MouseEvent('mousemove', {
  clientX: element.getBoundingClientRect().left + 3,
  clientY: element.getBoundingClientRect().top,
  bubbles: true,
  cancelable: true
});

const mouseUpEvent = new MouseEvent('mouseup', {
  bubbles: true,
  cancelable: true
});

// Dispatch the mousedown event to the element that has the listener
element.dispatchEvent(mouseDownEvent);

// For mousemove, the listener may be the parent or even the document
<element|document>.dispatchEvent(mouseMoveEvent);

// Dispatch mouseup to terminate the process
element.dispatchEvent(mouseUpEvent);

Run the code snippet. The square div element is draggable and you can click and drag it when the simulation timer is not running. Click the simulate button to see the simulation in action:

// Timer ID holder
let linearSimulationTimer;

// Simulation X/Y calculation
let calcX = 0, calcY = 0;

// Simulation X/Y axis orientation to handle parent collisions
let xAxisOrientation = 1, yAxisOrientation = 1;

// How many pixels to move the element for X/Y axis
const pixelsShift = 3;

// Elements
const simulateButton = document.getElementById('simulate-dnm');
const movable = document.getElementById('movable');
const movableContainer = movable.parentNode;

simulateButton.addEventListener('click', function() {  
  // If there is a timer running
  if (linearSimulationTimer) {
    // Stop and clear the timer
    clearInterval(linearSimulationTimer);
    linearSimulationTimer = null;
    
    // Create a simple mouseup event with no custom properties
    const mouseUpEvent = new MouseEvent('mouseup', {
      bubbles: true,
      cancelable: true,
    });
    
    // Dispatch it to the movable element
    movable.dispatchEvent(mouseUpEvent);

    // Handle button label text (start/stop)
    simulateButton.classList.remove('running');
  // Else if there is no timer running
  } else {
    // Create the mousedown event using movable element client left/top for event clientX.clientY
    const mouseDownEvent = new MouseEvent('mousedown', {
      clientX: movable.getBoundingClientRect().left,
      clientY: movable.getBoundingClientRect().top,
      pageX: 0,
      pageY: 0,
      bubbles: true,
      cancelable: true,
      view: window
    });

    // Dispatch the mousedown event to the movable element
    movable.dispatchEvent(mouseDownEvent);

    // Get movable parent client rect
    const parentRect = movable.parentNode.getBoundingClientRect();

    // Start the simulation timer
    linearSimulationTimer = setInterval(() => {
      // Get movable element size
      const { width, height } = movable.getBoundingClientRect();

      // Calculate new X/Y position and orientation
      calcX += pixelsShift * xAxisOrientation;
      calcY += pixelsShift * yAxisOrientation;

      // If we hit movable parent X axis bounds, reverse X axis
      if (calcX + width > parentRect.width) {
        calcX  = parentRect.width - width;
        xAxisOrientation = -xAxisOrientation;
      } else if (calcX < 0) {
        calcX = 0;
        xAxisOrientation = -xAxisOrientation;
      }

      // If we hit movable parent Y axis bounds, reverse Y axis
      if (calcY + height > parentRect.height) {
        calcY  = parentRect.height - height;
        yAxisOrientation = -yAxisOrientation;
      } else if (calcY < 0) {
        calcY = 0;
        yAxisOrientation = -yAxisOrientation;
      }

      // Create mousemove event using calcX/calcY and the parent client position
      const mouseMoveEvent = new MouseEvent('mousemove', {
        clientX: parentRect.left + calcX,
        clientY: parentRect.top + calcY,
        pageX: 0,
        pageY: 0,
        bubbles: true,
        cancelable: true,
        view: window
      });

      // Dispatch the mousemove event to the parent which it has the listener
      movableContainer.dispatchEvent(mouseMoveEvent);
    }, 50);
    
    // Handle button label text (start/stop)
    simulateButton.classList.add('running');
  }
});

// Mouse capture and drag handler (https://javascript.info/mouse-drag-and-drop)
movable.onmousedown = function(event) {
  let shiftX = event.clientX - movable.getBoundingClientRect().left;
  let shiftY = event.clientY - movable.getBoundingClientRect().top;

  moveAt(event.pageX, event.pageY);

  function moveAt(pageX, pageY) {
    movable.style.left = pageX - shiftX - movableContainer.offsetLeft + 'px';
    movable.style.top = pageY - shiftY - movableContainer.offsetTop + 'px';
  }

  function onMouseMove(event) {
    moveAt(event.pageX, event.pageY);
  }

  movableContainer.addEventListener('mousemove', onMouseMove);

  movable.onmouseup = function() {
    movableContainer.removeEventListener('mousemove', onMouseMove);
    movable.onmouseup = null;
  }
}

movable.ondragstart = function() {
  return false;
}

#movable-container {
  position: relative;
  height: 80px;
  width: 200px;
  margin: auto;
  margin-bottom: 20px;
  border: 1px dotted silver;
}

#movable {
  position: relative;
  left: 0;
  width: 30px;
  height: 30px;
  background-color: cornflowerblue;
  border-radius: 5px;
  border: 1px solid grey;
}

#simulate-dnm > span:before {
  content: 'Start ';
}

#simulate-dnm.running > span:before {
  content: 'Stop ';
}

<div id="movable-container">
  <div id="movable"></div>
</div>
<div>
  <button id="simulate-dnm"><span>Mouse capture & move simulation</span></button>
</div>

Simulating Drag n Drop

Please read inline comments

// We create 3 drag events using DragEvent interface,
// one for dragstart to initiate the process,
// one for drop to handle the drag element drop inside the drop container
// and one for dragend to terminate the process

const dragStartEvent = new DragEvent('dragstart', {
  bubbles: true,
  cancelable: true
});
const dragEndEvent = new DragEvent('dragend', {
  bubbles: true,
  cancelable: true
});
const dropEvent = new DragEvent('drop', {
  bubbles: true,
  cancelable: true
});

// Dispatch the dragstart event to the source element to initiate
sourceNode.dispatchEvent(dragStartEvent);

// Dispatch the drop event to the destination element to get the drag
destinationNode.dispatchEvent(dropEvent);

// Dispatch the dragend event to the source element to finish
sourceNode.dispatchEvent(dragEndEvent);

Run the code snippet and hit the simulate button to trigger the drag n drop events sequence:

// The current parent index that the drag element is inside
let currentParentIndex = 0;

// Elements
const simulateButton = document.getElementById('simulate-dnd');
const sourceNode = document.getElementById('drag');

function simulateDragDrop(sourceNode, destinationNode) {
  // Create dragstart event
  const dragStartEvent = new DragEvent('dragstart', {
    bubbles: true,
    cancelable: true
  });
  
  // Create dragend event
  const dragEndEvent = new DragEvent('dragend', {
    bubbles: true,
    cancelable: true
  });
  
  // Create drop event
  const dropEvent = new DragEvent('drop', {
    bubbles: true,
    cancelable: true
  });

  // Dispatch dragstart event to the draggable element
  sourceNode.dispatchEvent(dragStartEvent);
  
  // Dispatch drop event to container element we want to drop the draggable
  destinationNode.dispatchEvent(dropEvent);
  
  // Dispatch dragend  event to the draggable element
  sourceNode.dispatchEvent(dragEndEvent);
}

simulateButton.addEventListener('click', function() {
  // Change drop container index to other container than the current
  const newParentIndex = currentParentIndex === 0 ? 1 : 0;
  
  // Get the drop container element
  const destinationNode = document.getElementsByClassName('dropzone')[newParentIndex];

  // Initiate simulation sequence
  simulateDragDrop(sourceNode, destinationNode);

  // Save the new container index
  currentParentIndex = newParentIndex;
});


// Drag n Drop handling

let dragged;

document.addEventListener("dragstart", function(event) {
  // store a ref. on the dragged elem
  dragged = event.target;
  // make it half transparent
  event.target.style.opacity = .5;
}, false);

document.addEventListener("dragend", function(event) {
  // reset the transparency
  event.target.style.opacity = "";
}, false);

/* events fired on the drop targets */
document.addEventListener("dragover", function(event) {
  // prevent default to allow drop
  event.preventDefault();
}, false);

document.addEventListener("dragenter", function(event) {
  // highlight potential drop target when the draggable element enters it
  if (event.target.className == "dropzone") {
    event.target.style.background = "yellow";
  }
}, false);

document.addEventListener("dragleave", function(event) {
  // reset background of potential drop target when the draggable element leaves it
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
  }
}, false);

document.addEventListener("drop", function(event) {
  // prevent default action (open as link for some elements)
  event.preventDefault();
  // move dragged elem to the selected drop target
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
    dragged.parentNode.removeChild(dragged);
    event.target.appendChild(dragged);
    currentParentIndex = Array.prototype.indexOf.call(event.target.parentNode.children, event.target);
  }  
}, false);

.dropzones {
  display: flex;
  justify-content: space-evenly;
}

.dropzone {
  width: 100px;
  height: 100px;
  background-color: mintcream;
  border-radius: 5px;
  border: 2px dashed darkgrey;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 10px;
}

#drag {
  margin: unset;
  width: 40px;
  height: 40px;
  background-color: coral;
  border-radius: 4px;
  border: 1px solid grey; 
}

<div class="dropzones">
  <div class="dropzone">
    <div id="drag" draggable="true"></div>
  </div>
  <div class="dropzone"></div>
</div>
<div>
  <button id="simulate-dnd">Simulate Drag & Drop</button>
</div>

这篇关于在可拖动元素上模拟 3 像素拖动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆