Подтвердить что ты не робот

Как клонировать или повторно отправлять события DOM?

Я ищу простой и абстрактный способ клонирования или повторной отправки событий DOM. Я не заинтересован в клонировании узлов DOM.

Я немного экспериментировал, прочитал спецификацию DOM Events, и я не нашел четкого ответа.

В идеале я ищу что-то прямолинейное, как:

handler = function(e){
  document.getElementById("decoy").dispatchEvent(e)
}
document.getElementById("source").addEventListener("click", handler)

Этот пример кода, конечно, не работает. Там есть исключение DOM, указывающее, что событие в настоящее время отправляется - очевидно.

Я бы не хотел вручную создавать новые события с помощью document.createEvent(), инициализировать их и отправлять их.

Есть ли простое решение для этого варианта использования?

4b9b3361

Ответ 1

Я знаю, вопрос старый, и OP хотел избежать создания/инициализации подхода, но существует относительно простой способ дублирования событий:

new_event = new MouseEvent(old_event.type, old_event)

Если вы хотите больше, чем просто события мыши, вы можете сделать что-то вроде этого:

new_event = new old_event.constructor(old_event.type, old_event)

И в исходном контексте:

handler = function(e) {
  new_e = new e.constructor(e.type, e);
  document.getElementById("decoy").dispatchEvent(new_e);
}
document.getElementById("source").addEventListener("click", handler);

(Для пользователей jQuery вам может понадобиться e.originalEvent.constructor вместо e.constructor)

Ответ 2

Исправление Internet Explorer

Алексис опубликовал хорошее решение, но его решение не будет работать в Internet Explorer. Приведенное ниже решение будет. К сожалению, в Internet Explorer нет такой согласованной системы, как конструкторы событий, поэтому приведенный ниже код необходим.

var allModifiers = ["Alt","AltGraph","CapsLock","Control",
                    "Meta","NumLock","Scroll","Shift","Win"];
function redispatchEvent(original, newTargetId) {
  if (typeof Event === "function") {
    var eventCopy = new original.constructor(original.type, original);
  } else {
    // Internet Explorer
    var eventType = original.constructor.name;
    var eventCopy = document.createEvent(eventType);
    if (original.getModifierState)
      var modifiersList = allModifiers.filter(
        original.getModifierState,
        original
      ).join(" ");
    
    if (eventType === "MouseEvent") original.initMouseEvent(
      original.type, original.bubbles, original.cancelable,
      original.view, original.detail, original.screenX, original.screenY,
      original.clientX, original.clientY, original.ctrlKey,
      original.altKey, original.shiftKey, original.metaKey,
      original.button, original.relatedTarget
    );
    if (eventType === "DragEvent") original.initDragEvent(
      original.type, original.bubbles, original.cancelable,
      original.view, original.detail, original.screenX, original.screenY,
      original.clientX, original.clientY, original.ctrlKey,
      original.altKey, original.shiftKey, original.metaKey,
      original.button, original.relatedTarget, original.dataTransfer
    );
    if (eventType === "WheelEvent") original.initWheelEvent(
      original.detail, original.screenX, original.screenY,
      original.clientX, original.clientY, original.button,
      original.relatedTarget, modifiersList,
      original.deltaX, original.deltaY, original.deltaZ, original.deltaMode
    );
    if (eventType === "PointerEvent") original.initPointerEvent(
      original.type, original.bubbles, original.cancelable,
      original.view, original.detail, original.screenX, original.screenY,
      original.clientX, original.clientY, original.ctrlKey,
      original.altKey, original.shiftKey, original.metaKey,
      original.button, original.relatedTarget,
      original.offsetX, original.offsetY, original.width, original.height,
      original.pressure, original.rotation,
      original.tiltX, original.tiltY,
      original.pointerId, original.pointerType,
      original.timeStamp, original.isPrimary
    );
    if (eventType === "TouchEvent") original.initTouchEvent(
      original.type, original.bubbles, original.cancelable,
      original.view, original.detail, original.screenX, original.screenY,
      original.clientX, original.clientY, original.ctrlKey,
      original.altKey, original.shiftKey, original.metaKey,
      original.touches, original.targetTouches, original.changedTouches,
      original.scale, original.rotation
    );
    if (eventType === "TextEvent") original.initTextEvent(
      original.type, original.bubbles, original.cancelable,
      original.view,
      original.data, original.inputMethod, original.locale
    );
    if (eventType === "CompositionEvent") original.initTextEvent(
      original.type, original.bubbles, original.cancelable,
      original.view,
      original.data, original.inputMethod, original.locale
    );
    if (eventType === "KeyboardEvent") original.initKeyboardEvent(
      original.type, original.bubbles, original.cancelable,
      original.view, original.char, original.key,
      original.location, modifiersList, original.repeat
    );
    if (eventType === "InputEvent" || eventType === "UIEvent")
      original.initUIEvent(
        original.type, original.bubbles, original.cancelable,
        original.view, original.detail
      );
    if (eventType === "FocusEvent") original.initFocusEvent(
        original.type, original.bubbles, original.cancelable,
        original.view, original.detail, original.relatedTarget
    );
  }
  
  document.getElementById(newTargetId).dispatchEvent(eventCopy);
  if (eventCopy.defaultPrevented)  newTargetId.preventDefault();
}
<button onclick="redispatchEvent(arguments[0], '2nd')">Click Here</button>
<button id="2nd" onclick="console.log('Alternate clicked!')">Alternate Button</button>

Ответ 3

Как насчет запускающего события?

В вашем случае:

$('#decoy').trigger('click')

Или в чистом JS вы можете найти его в Как вызвать событие в JavaScript?


UPDATE

Я нашел способ через jQuery:


function clone_obj(obj){
    if(obj == null || typeof(obj) != 'object') return obj;
  var temp = new obj.constructor();
  for(var key in obj) temp[key] = clone_obj(obj[key]);
  return temp;
}