Порядок событий пузыря и захвата на цели - PullRequest
1 голос
/ 16 апреля 2020

Определен ли где-нибудь порядок событий Bubbling и Capturing во время целевой фазы?

Практически везде, где вы смотрите, вы обнаружите, что сначала есть фаза Capturing, а затем Bubbling. В некоторых источниках дополнительно упоминается целевая фаза в качестве отдельной стадии.

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

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

const extBox = document.querySelector('.external-box');
const intBox = document.querySelector('.internal-box');
const par = document.querySelector('p');

extBox.addEventListener('click', bubblingEvent, false);
intBox.addEventListener('click', bubblingEvent, false);
par.addEventListener('click', bubblingEvent, false);

par.addEventListener('click', capturingEvent, true);
extBox.addEventListener('click', capturingEvent, true);
intBox.addEventListener('click', capturingEvent, true);      
      
function bubblingEvent(event) {
  console.log(event.currentTarget.className + ': bubbling event, ' + getPhaseStr(event.eventPhase));
}
      
function capturingEvent(event) {
  console.log(event.currentTarget.className + ': capturing event, ' + getPhaseStr(event.eventPhase));
}

function getPhaseStr (eventPhase) {
  let eventPhaseStr;

  switch (eventPhase) {
    case 0:
      eventPhaseStr = 'NONE';
      break;
    case 1:
      eventPhaseStr = 'CAPTURING_PHASE';
      break;
    case 2:
      eventPhaseStr = 'AT_TARGET';
      break;
    case 3:
      eventPhaseStr = 'BUBBLING_PHASE';
      break;
    default:
      eventPhaseStr = 'ERROR';
  }

  return eventPhaseStr;
}
* {
  box-sizing: border-box;
}

.external-box, .internal-box {
  width: 50%;
  margin: 1rem;
  padding: 1rem;
}

.external-box {
  background-color: aquamarine;
}

.internal-box {
  background-color: blueviolet;
}

p {
  background-color: cornsilk;
  padding: 1rem;
}
<div class='external-box'>external-box
  <div class='internal-box'>internal-box
    <p class='par'>paragraph</p>
  </div>
</div>

В приведенном выше примере мы можем видеть, что - в течение целевой фазы - событие, добавленное для фазы пузырьков, выполняется до Фаза захвата. Это потому, что я сначала зарегистрировал события для фазы Bubbling. Если я сначала зарегистрирую события для фазы Capturing, а затем Bubbling, порядок будет «правильным».

Мой вопрос еще раз: определен ли где-нибудь порядок событий во время целевой фазы?

1 Ответ

0 голосов
/ 16 апреля 2020

Вы правы. Когда прослушиватель событий присоединен к элементу, и этот элемент является целью, не имеет значения, установлен ли прослушиватель событий для активации во время захвата или во время всплытия. Официальная спецификация описывает это здесь .

Для каждого слушателя в слушателях, чье удаленное значение равно false:

Если фаза "захватывает" и захват слушателя имеет значение false, тогда продолжайте.

Если фаза "пузырящаяся" и захват слушателя имеет значение true, тогда продолжить.

(в конечном итоге вызвать подключенного слушателя)

Когда на цели , фаза не захватывает и не пузырится, как показывает то, как ваша функция getPhaseStr анализирует eventPhase. Таким образом, ни 3. continue, ни 4. continue не активируются, поэтому слушатель в конечном счете вызывается в том порядке, в котором слушатели были подключены. (Порядок слушателей сохраняется в «списке слушателей событий» , списке слушателей, прикрепленных к определенному элементу)

b1.addEventListener('click', () => console.log('bubbling'));
b1.addEventListener('click', () => console.log('capturing'), true);

b2.addEventListener('click', () => console.log('capturing'), true);
b2.addEventListener('click', () => console.log('bubbling'));
<button id="b1">click</button>
<button id="b2">click</button>
...