javascript - 在 Web 组件中获取事件目标

标签 javascript dom events web-component shadow-dom

anchor 元素 ( <a> ) 是在用户与网络组件交互时创建的。问题是,当单击 anchor 时,我无法从 Web 组件的“外部”获取返回的 anchor 元素。

我向 document 添加了一个事件监听器监听点击事件。当单击 DOM 中某处的元素时,我期望 e.target成为被点击的元素。 在 Web 组件内某处单击的情况下,将返回自定义元素 ( <fancy-list></fancy-list> ),而不是单击的元素。

当影子DOM的模式设置为open时DOM 应该是可访问的。

class Fancylist extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });

    const wrapper = document.createElement('div');
    wrapper.innerHTML = `<ul></ul><button>Add item</button>`;

    shadow.appendChild(wrapper);

    this.on_root_click = this.on_root_click.bind(this);
  }

  connectedCallback() {
    this.ul_elm = this.shadowRoot.querySelector('ul');
    this.shadowRoot.addEventListener('click', this.on_root_click, false);
  }

  on_root_click(e){
    switch(e.target.nodeName){
      case 'BUTTON':
        this.ul_elm.innerHTML += '<li><a href="p1">List item</a></li>';
        break;
      case 'A':
        e.preventDefault();
        console.log('You clicked a link!');
        break;
    }
  }
}

customElements.define('fancy-list', Fancylist);
<!DOCTYPE html>
<html>
  <head>
    <title>List</title>
    <meta charset="utf-8" />
    <script type="text/javascript">
      document.addEventListener('DOMContentLoaded', e => {
        document.body.addEventListener('click', e => {
          //console.log(e.composedPath());
          console.log(e.target); // why is this not returning an anchor element when an anchor is clickend inside the <fancy-list>?
        }, false);
      }, false);
    </script>
  </head>
  <body>
  <h1>List</h1>
  <fancy-list></fancy-list>
  </body>
</html>

最佳答案

Shadow DOM 的目的正是从容器的 Angular 屏蔽 Shadow DOM 的 HTML 内容。

这也是为什么重新定位内部事件以暴露 Shadow DOM 宿主的原因。

但是,您仍然可以通过获取 Event.path 数组属性的第一项来获取真正的目标。

event.path[0]

注意:当然它只适用于open Shadow DOM。

class Fancylist extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });

    const wrapper = document.createElement('div');
    wrapper.innerHTML = `<ul></ul><button>Add item</button>`;

    shadow.appendChild(wrapper);

    this.on_root_click = this.on_root_click.bind(this);
  }

  connectedCallback() {
    this.ul_elm = this.shadowRoot.querySelector('ul');
    this.shadowRoot.addEventListener('click', this.on_root_click, false);
  }

  on_root_click(e){
    switch(e.target.nodeName){
      case 'BUTTON':
        this.ul_elm.innerHTML += '<li><a href="p1">List item</a></li>';
        break;
      case 'A':
        e.preventDefault();
        break;
    }
  }
}

customElements.define('fancy-list', Fancylist);
<!DOCTYPE html>
<html>
  <head>
    <title>List</title>
    <meta charset="utf-8" />
    <script type="text/javascript">
      document.addEventListener('DOMContentLoaded', e => {
        document.body.addEventListener('click', e => {
          console.log(e.path[0]);
        }, false);
      }, false);
    </script>
  </head>
  <body>
  <h1>List</h1>
  <fancy-list></fancy-list>
  </body>
</html>

2021 年更新

如评论所述,您现在应该使用 event.composedPath()

关于javascript - 在 Web 组件中获取事件目标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57963312/

相关文章:

javascript - 有人可以解释一下 e = e || X?为什么要把e赋值给e?

javascript - 无法读取 null 的属性 'paused'

events - 模型更改时的 emberjs 事件

javascript - 使用 jQuery 解析文本

javascript - 操作使用 'vanilla' javascript 动态添加的 HTML 元素

javascript - 使用模板字符串附加 HTML

JavaScript:将 HTML 列表分成两半

javascript - 使用 jQuery 加载图像后如何触发函数?

javascript - 尝试单击时菜单不会保持打开状态

javascript - 如何使用一个默认条件对 3 个条件执行三元语句