Почему event.offsetX / Y предоставляет разные значения в Firefox / Edge против Chrome? - PullRequest
0 голосов
/ 14 января 2020

Возможно, мой Google-фу сегодня действительно плохой, но я не смог найти объяснения этому странному поведению, которое я заметил.

У меня есть событие mousemove слушателя на родительский узел, но иногда event.target является дочерним узлом. На Chrome (v79, а также на удивление Safari) значение event.offsetX/Y является неизменным, независимо от того, является ли цель узлом root или дочерним узлом. В Firefox (v72.0.1) и Edge event.offsetX/Y внезапно оказывается относительно дочернего узла, если дочерний узел является целью. Это отбрасывает мою функцию обработки событий, так как для нее требуется положение мыши относительно узла слушателя root.

Я смотрел на использование event.layerX/Y, что последовательно аналогично offsetX / Y на родительский узел, но не всегда равный, когда он является дочерним узлом.

Я не могу обмануть и использовать CSS pointer-events:none, потому что у меня все еще есть обработчики щелчков на этих дочерних узлах.

Есть ли простой способ гарантировать, что event.target - это узел, на котором я установил прослушиватель событий, или всегда получать положение мыши относительно родительского / слушающего узла?

1 Ответ

1 голос
/ 14 января 2020

Правильное поведение, которое вы описываете как Firefox, так как specs запрашивает, чтобы значения .offsetN относились к " целевому узлу ".
Мой Chrome, кстати, также раскрывает это поведение.

Но вы можете воспроизвести желаемое, отправив новое синтетическое c Событие, основанное на реальном. Таким образом, все браузеры согласятся, что существует только один целевой узел , и значения .offsetN всегда будут относительно него.

// static logger
const _log = document.getElementById('_log');
const log = (...vals) => {
 _log.textContent += vals.map(v => JSON.stringify(v)).join(' – ') + '\n';
}
const clearLog = () => { _log.textContent = "";}

// actual code
document.getElementById('parent').onmousemove = function(e) {
  // new true event
  if(e.isTrusted) { clearLog(); }
  // in case we are not the true target
  if(e.target !== e.currentTarget) {
    // create a synthetic event
    const synth = new MouseEvent('mousemove', { clientX: e.clientX, clientY: e.clientY});
    // dispatch it *synchronously* on us
    e.currentTarget.dispatchEvent(synth);

    // to show it would have been wrong in FF
    log('originals ', e.offsetX, e.offsetY);
    return;
  }
  // here the values are consistent
  log(e.isTrusted ? 'originals ' : 'synthetics', e.offsetX, e.offsetY);
};
#_log {
  background: #EEE;
  height: 3em;
  padding: 2px;
}
#parent {
  border: 1px solid;
  width: 400px;
  height: 200px;
}
#child {
  border: 1px solid;
  transform: translate(150px, 50px);
  width: 100px;
  height: 100px;
}
...