8

I'm trying to understand what events that originate in light DOM look like when received in shadow DOM via a <content> element. I'm reading the Shadow DOM W3C Draft, and I don't entirely understand it but it sounds like events are to be "retargeted" from the point of view of the EventListener attachment.

In the cases where event path is across multiple node trees, the event's information about the target of the event is adjusted in order to maintain encapsulation. Event retargeting is a process of computing relative targets for each ancestor of the node at which the event is dispatched. A relative target is a node that most accurately represents the target of a dispatched event at a given ancestor while maintaining the encapsulation.

and

At the time of event dispatch:

  • The Event target and currentTarget attributes must return the relative target for the node on which event listeners are invoked

So here's a simple Polymer custom element that just puts its children into a container, and adds a click EventListener to the container (in the shadow DOM). In this case the child is a button.

<!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>

When I run this on Chrome 38.0.2075.0 canary, when I click on the button I get:

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

and when I click on the container I get:

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

So I get an event target in either the light or shadow DOM, depending on which DOM the source element was in. I was expecting to get a target from the shadow DOM in both cases because that's where the EventListener is attached. My questions are:

  1. Is this the way it is supposed to work, and
  2. If so, is there an alternative way to get events that bubble up from the light DOM retargeted to the shadow DOM?

In case someone wants to ask, "What are you trying to do?", I'm not trying to do anything specifically other than understand the behavior.

4

1 回答 1

14

shadow dom 的事件很棘手。我尝试在下面捕获一个大脑转储。

  1. 这是它应该工作的方式吗

是的。如果你在 Chrome 中测试,你会得到原生 shadow dom。


我在HTML5Rocks - Shadow DOM 301文章中写了一个关于事件重定向的部分。基本上,重定向意味着源自 shadow dom 的事件看起来像是来自元素本身。

在您的示例中,您将事件记录在 shadow dom 内部,因此仍然可以看到它。如果您还在元素之外添加了一个“点击”侦听器,那么目标看起来就好像它来自该元素:

<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在顶级示例中看到的原因。为什么你会看到它?您看到它是因为该按钮不是您元素的 shadow dom 的一部分。它在 light dom 和元素的目标中。重要的是要记住轻 DOM 节点在逻辑上仍然在主文档中。它们没有移动到 shadow dom 中,只是在<content>插入点处渲染。


顺便说一句,您的示例有几个聚合修复:

  1. this.shadowRoot.querySelector('#internalcontainer')-> this.$.internalcontainerthis.$.ID是 Polymer 的“自动节点查找”功能。
  2. 你根本不需要使用addEventListener()。相反,使用<div id="internalcontainer" on-click="{{clickHandler}}">. 这是一个声明性事件处理程序。
于 2014-06-30T03:24:31.703 回答