Как нацелены на события Shadow DOM из-под ‹content›?

Я пытаюсь понять, как выглядят события, возникающие в световой модели DOM, полученные в теневой модели DOM через элемент <content>. Я читаю Shadow DOM W3C Draft и не полностью понимаю это, но похоже, что события должны быть «перенаправлены» с точки зрения вложения EventListener.

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

а также

Во время отправки события:

  • Атрибуты Event target и currentTarget должны возвращать относительную цель для узла, на котором вызываются прослушиватели событий.

Итак, вот простой настраиваемый элемент Polymer, который просто помещает своих дочерних элементов в контейнер и добавляет к контейнеру прослушиватель событий щелчка (в теневой DOM). В этом случае ребенок - это кнопка.

<!DOCTYPE html>
<html>
  <head>
    <script src="bower_components/platform/platform.js"></script>
    <link rel="import" href="bower_components/polymer/polymer.html">
  </head>
  <body unresolved>
    <polymer-element name="foo-bar">
      <template>
        <div id="internal-container" style="background-color:red; width:100%;">
          <content></content>
        </div>
      </template>
      <script>
       Polymer("foo-bar", {
         clickHandler: function(event) {
           console.log(event);
           var element = event.target;
           while (element) {
             console.log(element.tagName, element.id);
             element = element.parentElement;
           }
         },

         ready: function() {
           this.shadowRoot.querySelector('#internal-container').addEventListener('click', this.clickHandler);
         }
       });
      </script>
    </polymer-element>

    <foo-bar id="custom-element">
      <button>Click me</button>
    </foo-bar>
  </body>
</html>

Когда я запускаю это в Chrome 38.0.2075.0 canary, когда я нажимаю кнопку, я получаю:

MouseEvent {dataTransfer: null, toElement: button, fromElement: null, y: 19, x: 53…}altKey: falsebubbles: truebutton: 0cancelBubble: falsecancelable: truecharCode: 0clientX: 53clientY: 19clipboardData: undefinedctrlKey: falsecurrentTarget: nulldataTransfer: nulldefaultPrevented: falsedetail: 1eventPhase: 0fromElement: nullkeyCode: 0layerX: 53layerY: 19metaKey: falsemovementX: 0movementY: 0offsetX: 45offsetY: 10pageX: 53pageY: 19path: NodeList[0]relatedTarget: nullreturnValue: truescreenX: 472screenY: 113shiftKey: falsesrcElement: buttontarget: buttontimeStamp: 1404078533176toElement: buttontype: "click"view: WindowwebkitMovementX: 0webkitMovementY: 0which: 1x: 53y: 19__proto__: MouseEvent test.html:17
BUTTON  test.html:20
FOO-BAR custom-element test.html:20
BODY  test.html:20
HTML  test.html:20

и когда я нажимаю на контейнер, я получаю:

MouseEvent {dataTransfer: null, toElement: div#internal-container, fromElement: null, y: 15, x: 82…} test.html:17
DIV internal-container test.html:20

Таким образом, я получаю цель события либо в световой, либо в теневой DOM, в зависимости от того, в какой DOM находился элемент source. Я ожидал получить цель из теневой DOM в обоих случаях, потому что там EventListener прилагается. Мои вопросы:

  1. Так ли это должно работать, и
  2. Если да, то есть ли альтернативный способ получить события, которые всплывают из светлого DOM, перенаправленного на теневой DOM?

В случае, если кто-то хочет спросить: «Что вы пытаетесь сделать?», Я не пытаюсь делать что-то конкретное, кроме как понять поведение.


person rhashimoto    schedule 29.06.2014    source источник


Ответы (1)


События с теневым домом сложны. Я пытаюсь сделать снимок ниже.

  1. Так оно и должно работать?

Ага. Если вы тестируете в Chrome, вы получаете нативную теневую среду.


Я написал раздел о ретаргетинге событий в HTML5Rocks - Shadow DOM 301 статья. По сути, ретаргетинг означает, что события, происходящие в теневом домене, выглядят так, как будто они исходят от самого элемента.

В вашем примере вы регистрируете событие внутри теневого домена, поэтому оно все еще там отображается. Если вы также добавите прослушиватель щелчка вне элемента, цель будет выглядеть так, как если бы она пришла из элемента:

<script>
  var el = document.querySelector('#custom-element');
  el.addEventListener('click', function(e) {
    console.log(e.target.tagName); // logs FOO-Bar
  });
</script>

http://jsbin.com/womususe/1/edit

Пузырьки событий «щелчок». Вот почему вы видите BUTTON в своем верхнем примере. Почему ты вообще это видишь? Вы видите это, потому что кнопка не является частью теневой области вашего элемента. Это световой дом и цель элемента. Важно помнить, что легкие узлы DOM по-прежнему находятся в основном документе. Они не перемещаются в теневую область, а просто отображаются в <content> точках вставки.


Кстати, в ваших примерах есть пара полимеризованных исправлений:

  1. this.shadowRoot.querySelector('#internalcontainer') -> this.$.internalcontainer. this.$.ID - это функция Polymer «автоматический поиск узлов».
  2. Вам вообще не нужно использовать addEventListener(). Вместо этого используйте <div id="internalcontainer" on-click="{{clickHandler}}">. Это декларативный обработчик событий.
person ebidel    schedule 30.06.2014
comment
Спасибо за ответ (и всю другую информацию, которую вы публикуете в мире)! Я понимаю, что кнопка не является частью теневого DOM; вот почему я удивлен, увидев это на слушателе теневого DOM. В спецификации говорится, что атрибуты Event target и currentTarget должны возвращать относительную цель для узла, на котором вызываются прослушиватели событий. поэтому я ожидал, что события будут перенаправлены при прохождении через элемент <content>. Чтобы быть предельно ясным, вы говорите, что он соответствует спецификации для теневого прослушивателя DOM для получения целей событий от DOM своего хоста, а также от его собственного DOM? - person rhashimoto; 30.06.2014
comment
Да это нормально. Ретаргетинг событий идет в другом направлении: предотвращение того, чтобы внешний DOM видел узлы внутри ShadowDOM. - person Scott Miles; 30.06.2014
comment
@ScottMiles Допустим, элемент на уровне -10 в теневой DOM запускает событие ответа. Через ретаргетинг он будет распространяться на все 10 уровней (хостов) выше. В то же время элемент на уровне -5 также запускает событие с именем response, и для этого также происходит перенацеливание. Если на уровне -4 вы хотите прикрепить обработчик для события ответа на уровне -5 (не зная о том, что запущено на уровне -10), он неохотно также обработает событие, исходящее от -10. Вы не можете знать все события, происходящие из глубины под водой, в среднем или большом приложении. Каково ваше мнение по этому поводу? Спасибо. - person adriann; 11.01.2018