имитировать 3-х пиксельное перетаскивание на элемент - PullRequest
6 голосов
/ 23 апреля 2020

Я просто пытаюсь смоделировать маленький щелчок и перетащить на перетаскиваемый элемент div - я нашел здесь несколько похожих вопросов о SO, но все они связаны с использованием дополнительных плагинов ...

Есть ли обычная JavaScript или jQuery способность обрабатывать конкретно перетаскивание? как я знаю .click(); или мышь можно вызвать для инициации.

Я не пытаюсь создать способность перетаскивания, у меня уже есть это. Я пытаюсь создать небольшую функцию, которая автоматически имитирует это событие. нажмите> удерживайте> перетащите вверх на 3 пикселя


Обновление: Невозможно найти что-либо об этом в SO или в другом месте без использования сторонней библиотеки, поэтому создание Награда 500 на это. Конечно, это возможно.

Ответы [ 2 ]

10 голосов
/ 01 мая 2020

Вы можете симулировать события мыши, используя интерфейс MouseEvent, и перетаскивать события, используя интерфейс DragEvent. Вы должны запустить правильную последовательность, используя EventTarget.dispatchEvent().

Я предполагаю, что вы объединяете "HTML Drag and Drop API" с "Мышью events " для создания поведения перетаскивания, поэтому я предоставлю один для имитации Drag & Drop и один для имитации Захват мыши и движение мыши .

Имитация Захват мыши и движение мыши

Пожалуйста, прочитайте встроенные комментарии

// 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);

Запустите фрагмент кода. Элемент квадратного div можно перетаскивать, и вы можете щелкнуть и перетащить его, когда таймер моделирования не работает. Нажмите кнопку симуляции, чтобы увидеть симуляцию в действии:

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

Имитация Drag n Drop

Пожалуйста, прочитайте встроенные комментарии

// 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);

Запустите фрагмент кода и нажмите кнопку имитации, чтобы вызвать последовательность событий перетаскивания n:

// 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 голосов
/ 30 апреля 2020

Если вы имеете в виду «имитация перетаскивания», вы вызываете событие mousedown, а затем обновляете положение элемента, который вы должны сделать, например, так:

let element = document.getElementById('draggable-div');
element.dispatchEvent(new Event('mousedown'));
element.style.top += 3

Это изменение style.top может или может не перемещать элемент в зависимости от того, как он расположен (абсолютный, относительный, закрепленный).

Если у вас есть библиотека перетаскивания, которую вы пытаетесь вызвать. Тогда вы можете даже смоделировать перетаскивание, просто переместив элемент в зону перетаскивания (на 3 пикселя вверх), а затем запустив mouseup:

let element = document.getElementById('draggable-div');
element.style.top += 3
element.dispatchEvent(new Event('mouseup'));

И этот список можно продолжить, поскольку теперь также перетаскиваются события ( хотя они еще не полностью поддерживаются всеми браузерами: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API).

Но из вашего вопроса неясно, для какой симуляции вы собираетесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...