Как клонировать или повторно отправлять события DOM?
Я ищу простой и абстрактный способ клонирования или повторной отправки событий DOM. Я не заинтересован в клонировании узлов DOM.
Я немного экспериментировал, прочитал спецификацию DOM Events, и я не нашел четкого ответа.
В идеале я ищу что-то прямолинейное, как:
handler = function(e){
document.getElementById("decoy").dispatchEvent(e)
}
document.getElementById("source").addEventListener("click", handler)
Этот пример кода, конечно, не работает. Там есть исключение DOM, указывающее, что событие в настоящее время отправляется - очевидно.
Я бы не хотел вручную создавать новые события с помощью document.createEvent()
, инициализировать их и отправлять их.
Есть ли простое решение для этого варианта использования?
Ответы
Ответ 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;
}