<body>
<button onclick = "myFunction()">CLICK</button>
<script>
function myFunction(event) {
// do something based on the value of the event's property
}
</script>
</body>
<body>
<button id = "myButton">CLICK</button>
<script>
var button = document.getElementById("myButton");
button.addEventListener("click", myFunction);
function myFunction(event) {
// do something based on the value of the event's property
}
</script>
</body>
Я мог бы добавить события нажатия на кнопку двумя описанными выше способами.
Я хочу изменить некоторые свойства объекта события, который myFunction получит перед выполнением.
Например, в событии клика событие имеет свойства clientX и clientY, и, предполагая, что исходные значения равны 100 и 100, я хочу, чтобы они были 150 и 150 (как они изменяются, определяется определенными условиями), а другие значения свойств быть такими же, как исходные значения.
Есть ли способ добиться этого?
Мне понадобилось измененное событие, потому что по какой-то причине я добавил атрибуты стиля scale, width к элементу body, из-за чего координатные точки, связанные с положением, рассчитывались неправильно.
Некоторые события, связанные с координатными точками, такие как click, drag, ведут себя некорректно.
По сути, каждый объект события, связанный с точкой, должен быть исправлен, особенно MouseEvent, PointerEvent.
Согласно @Mr. Polywhirl, мне нужно сначала написать функцию для обработки объекта события, а затем вызвать фактический обратный вызов в функции обработки, которая более реплицирована.
Можно ли добиться бессмысленной модификации, изменив addEventListener на прототипе?
Если это работает, как привязка, такая как <button onclick = "myFunction(event)">CLICK</button>, может добиться такой же модификации события?
Нажмите F12 на этой странице, чтобы открыть консоль, и введите document.body.style = "scale: 0.8;width: 125%;transform-origin: 0 0;" в консоли.
Затем нажмите на recent inbox messages в верхней части страницы, что, вероятно, вы и видите.
@ lai9fox ... ОП может проверить поздно предоставленное, но очень удобное решение проблемы ОП.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам нужно будет сделать копию события, так как свойства clientX и clientY доступны только для чтения.
Перехватите событие в другой функции, измените событие и отправьте его исходному обработчику.
var button = document.getElementById('myButton');
button.addEventListener("click", myModifiedFunction);
function myModifiedFunction(event) {
// The clientX and clientY properties are read-only
const { clientX, clientY, ...rest } = event;
// We need to make a copy of the event object information
const eventCopy = { clientX, clientY, ...rest };
// Mutate the (x, y) coordinates with an offset of (1,000, 1,000)
eventCopy.clientX += 1000;
eventCopy.clientY += 1000;
// Call the original handler
myFunction(eventCopy);
}
// Original click handler callback
function myFunction(event) {
const point = {
x: event.clientX,
y: event.clientY
};
console.info(`Point: ${JSON.stringify(point)}`);
}<button onclick = "myFunction(event)">CLICK</button>
<button id = "myButton">CLICK (MODIFIED)</button>Если вы хотите правильно клонировать событие, вы можете попробовать:
var button = document.getElementById('myButton');
button.addEventListener("click", myModifiedFunction);
function myModifiedFunction(event) {
// We need to make a copy of the event object information
const eventCopy = cloneEvent(event);
// Mutate the (x, y) coordinates with an offset of (1,000, 1,000)
Object.assign(eventCopy, {
clientX: eventCopy.clientX + 1000,
clientY: eventCopy.clientY + 1000
});
// Call the original handler
myFunction(eventCopy);
}
// Original click handler callback
function myFunction(event) {
const point = {
x: event.clientX,
y: event.clientY
};
console.info(`Point: ${JSON.stringify(point)}`);
}
// Adapted from: https://stackoverflow.com/a/39669794/1762224
function cloneEvent(e) {
if (!e) return;
const clone = new Function();
for (let p in e) {
let d = Object.getOwnPropertyDescriptor(e, p);
if (d && (d.get || d.set)) Object.defineProperty(clone, p, d);
else clone[p] = e[p];
}
Object.setPrototypeOf(clone, e);
return clone;
}<button onclick = "myFunction(event)">CLICK</button>
<button id = "myButton">CLICK (MODIFIED)</button>Привет! Я только что добавил некоторую информацию к этому вопросу. Любые другие предложения? @Мистер. Поливихрь
@lai9fox нравятся относительные/абсолютные координаты?
Нажмите F12 на этой странице, чтобы открыть консоль, и введите document.body.style = "scale: 0.8;width: 125%;transform-origin: 0 0;" в консоли. Затем нажмите на последние входящие сообщения в верхней части страницы, что, вероятно, вы и видите.
@Mr.Polywhirl ... Объект event не нужно копировать. Нужно просто переопределить clientX и clientY непосредственно в исходной ссылке на событие, например. Object.defineProperties.
Общее решение с Proxy для изменения события.
Вы можете создать глобальный объект-получатель, чтобы исправить значения ваших событий, во фрагменте есть исправление, чтобы сделать event.clientX/Y координаты указателя относительно целевого элемента для всех элементов внутри выбранного элемента контейнера:
var button = document.getElementById('myButton');
const _add = HTMLElement.prototype.addEventListener;
// monkey patch our event handlers for our canvas element only
HTMLElement.prototype.addEventListener = function(name, fn, ...args){
return _add.call(this, name, event => {
if (event instanceof MouseEvent && event.target.closest('#\\$canvas')){
return proxify(clientEvent, fn)(event);
}
return fn.call(this, event);
});
};
// corrects clientX and clientY to be relative to the target element
const clientEvent = {
clientX(val){
const rect = this.target.getBoundingClientRect();
return Math.round(val - rect.left);
},
clientY(val){
const rect = this.target.getBoundingClientRect();
return Math.round(val - rect.top);
}
};
// add mouse handlers for the both canvases
'mousemove mousedown mouseup'.split(' ').forEach(name => $canvas.addEventListener(name, myFunction));
'mousemove mousedown mouseup'.split(' ').forEach(name => $canvas2.addEventListener(name, myFunction));
// Original cliekc handler callback
function myFunction(event) {
const point = {
x: event.clientX,
y: event.clientY
};
$log.insertBefore(document.createElement('div'), $log.children[0]).textContent = `Point: ${JSON.stringify(point)}`;
}
function proxify(getters, fn) {
return obj => {
const proxy = new Proxy(obj, {
get(target, prop, receiver){
if (prop in getters){
return getters[prop].bind(obj)(obj[prop]);
}
return obj[prop];
}
});
return fn(proxy);
}
}[id=\$canvas]{
margin:10px;
background:lightgray;
border-radius:4px;
width:200px;
height:100px;
}
[id=\$canvas2]{
margin:10px;
background:lightgray;
border-radius:4px;
width:200px;
height:100px;
}
body{
display:flex;
}
[id=\$log]{
font-size:12px;
}<div id = "$canvas"></div>
<div id = "$canvas2"></div>
<div id = "$log"></div>Привет! Я только что добавил некоторую информацию к этому вопросу. @ Александр Ненашев
@lai9fox сделан в подходящем для всех событий указателя
Спасибо за ваш ответ @Alexander Nenashev Нажмите F12 на этой странице, чтобы открыть консоль, и введите document.body.style = "scale: 0.8;width: 125%;transform-origin: 0 0;"; в консоли. Затем нажмите recent inbox messages в верхней части страницы, что, вероятно, вы и видите. Это краткий пример того, как я модифицировал элемент body, к сожалению, вычисление getBoundingClientRect также подвержено ошибкам.
@lai9fox обновил ответ с помощью исправления обезьяны, поэтому вам не нужно устанавливать обработчики событий вручную.
@lai9fox lai9fox, если вам нравится мой ответ, вы можете принять его (флажок) и проголосовать (стрелка вверх). таким образом, я буду вознагражден и мотивирован, чтобы помогать вам дальше...
@lai9fox обновил окончательное решение, выглядит потрясающе
Эта или подобные задачи могут быть описаны как модификация метода, которая представляет собой манипулирование управлением функцией/методом и/или потоком данных.
Такое поведение причины может быть реализовано на более высоком уровне абстракции, например. around, before, after, afterThrowing и afterFinally модификаторы.
ОП ищет модификацию, которая происходит до вызова исходного метода.
В приведенном ниже коде показана исходная обработка события click обработчиком handleClickEvent и обработанная обработка события модифицированной версией той же самой функции handleClickEvent. Последний использует также предоставленную возможную реализацию модификатора before.
Затем все решение сводится к 3 небольшим функциям: реализации модификатора before, фактическому/оригинальному обработчику кликов и дополнительной функции, которая манипулирует данными события...
function handleClickEvent(evt) {
const mouseCoords = {
x: evt.clientX,
y: evt.clientY,
};
console.info({ mouseCoords });
}
function manipulateEventData([evt]) {
// - manipulate the original event's data.
Object.defineProperties(evt, {
clientX: {
value: evt.clientX + 1000,
},
clientY: {
value: evt.clientY + 1000,
},
});
}
document
.querySelector(`[data-original-handler]`)
.addEventListener('click', handleClickEvent);
document
.querySelector(`[data-modified-handler]`)
.addEventListener(
'click',
modifyBefore(handleClickEvent, manipulateEventData)
);<button data-original-handler>original click handler</button>
<button data-modified-handler>modified click handler</button>
<script>
function modifyBefore(proceed, handler, target = null) {
// - `target` equals the `this` context of the to be modified method.
return (
typeof proceed === 'function' &&
typeof handler === 'function' &&
function beforeType(...args) {
// - the target/context of the initial modifier/modification time
// still can be overruled by a handler's apply/call time context.
const context = this ?? target;
// - invocation of the `before` handler.
handler.call(context, args);
// - proceed with invoking the original function/method.
return proceed.apply(context, args);
}
) || proceed;
}
</script>@ lai9fox ... ОП может проверить приведенное выше, поздно предоставленное, но очень удобное решение проблемы ОП.
Свойства объекта Event доступны только для чтения.