addEventListener在自定义元素中不起作用。

问题描述 投票:1回答:1

我正在为我的网站制作一个大富翁游戏,我遇到了一个问题,就是我无法在自定义元素中为 "i "元素添加事件监听器。

这是我的自定义元素。

class Popup extends HTMLElement {
  constructor() {
    super();
    var that = this;

    var shadow = this.attachShadow({mode: 'open'});
    var wrapper = document.createElement('div');
    wrapper.setAttribute("class","popup-wrapper");
    var popup = document.createElement('div');
    popup.setAttribute('class','popup');

    let exitButton = document.createElement('i');
    exitButton.className = "fas fa-times fa-lg exit";

    exitButton.addEventListener("click", function () {
      console.log('a');
    });

    // styles
    var style = document.createElement('style');
    style.textContent = `
      @import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css");
      @import url("https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css");

      .popup-wrapper {
        position: fixed;
        top: 0; left: 0; right: 0; bottom: 0;
        background-color: rgba(0, 0, 0, .6);
        z-index: 9999;
        visibility: visible;
      }

      .popup {
        position: fixed;
        top: 50%; left: 50%;
        transform: translate(-50%, -50%);
        border: 1px solid #d6d6d6;
        background-color: #fff;
        border-radius: .25rem;
        padding: 1rem 2rem;
      }

      /* .exit {
        position: absolute;
        top: .5rem; right: .5rem;
        cursor: pointer;
      } */
    `;


    popup.appendChild(exitButton);

    wrapper.appendChild(popup);

    shadow.appendChild(style);
    shadow.appendChild(wrapper);

    this.isOpen = false;
    this.popup_wrapper = wrapper;
    this.popup = popup;
    this.exitButton = exitButton;
  }

  close() {
    console.log('a');
    this.remove();
  }
}

class TextPopup extends Popup {
  constructor() {
    super();

  }

  show() {
    this.exitButton.addEventListener("click", function () {
      console.log('a');
    });

    this.heading = this.getAttribute("heading");
    this.text = this.getAttribute("text");

    this.popup.innerHTML += `
      <h1>${this.heading}</h1>
      <p>${this.text}</p>
    `;
  }
}

customElements.define('text-popup', TextPopup);

我试着把它放在多个位置 但还是不行

我也有另一个自定义元素,其中addEventListener工作。

class Copy extends HTMLElement {
  constructor() {
    super();

    if (!this.hasAttribute('text')) return console.error("Text is not specified");

    this.text = this.getAttribute('text');
    this.style.cursor = "pointer";
    var that = this;
    this.addEvents(["click", "touchend"], () => {
      that.copy(that.text)
    });
  }

  copy(text) {
    navigator.clipboard.writeText(text).then(function() {
      // successfull
    }, function(err) {
      // unsuccessfull
    });
  }
}

customElements.define('copy-button', Copy);

PS:addEvents原型。

Element.prototype.addEvents = Document.prototype.addEvents = Window.prototype.addEvents = function (events, callback) {
  for (var i = 0; i < events.length; i++) this.addEventListener(events[i], callback);
};

我使用的是chrome的最后一个版本。

javascript class addeventlistener custom-element
1个回答
0
投票

所以感谢 @Jared Smith@Ken yo,我有这个解决方案。

我发现有 path,它是一个数组,包含了所有点击的路径。

class TextPopup extends Popup {
  constructor() {
    super();
  }

  connectedCallback() {
    document.body.addEventListener("click", function (e) {
      if (e.path[0].classList.contains("exit")) {
        console.log("exitButton was clicked!");
      }
    });
  }

  show() {
    this.heading = this.getAttribute("heading");
    this.text = this.getAttribute("text");

    this.popup.innerHTML += `
      <h1>${this.heading}</h1>
      <p>${this.text}</p>
    `;
  }
}

0
投票

一些提示。

  • 在shadowDOM中使用FontAwesome和Bootstrap CSS。 需要在主文档中加载CSS

  • 对于在shadowDOM中的单次点击,你不需要使用事件 听众 (技术,用于添加多个听众),设置 onclick 事件 处理人 会做

  • 使用 <TEMPLATE> 而不是用JS创建HTML,这样更不容易出错(而且更简单,代码更少,而且......)。

  • 发出你自己的 CustomEvent 与dispatchEvent一起使用,省去了处理这些事件的时间。path[0] 全局事件监听器中的数据

注意:这个SO片段中的CSS加载会在点击后造成3秒的延迟......仅在StackOverflow上。

<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">

<fa-button icon="fa-bars"></fa-button>
<div id=buttonbar>
  <fa-button icon="fa-address-card"></fa-button>
  <fa-button icon="fa-camera"></fa-button>
  <fa-button icon="fa-window-close"></fa-button>
</div>

<style>
  body {
    font-size: 48px; /* font settings cascade into shadowDOM */
  }
  #buttonbar {
    --buttonbackground: "grey"; /* CSS properties cascade into shadowDOM */
    --buttoncolor: black;
    float: right;
  }
</style>

<template id="FA-BUTTON">
  <style>
    @import url("//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css");
    :host {
      display: inline-block;
    }
    i {
      background: var(--buttonbackground, yellow);
      color: var(--buttoncolor, red);
    }
  </style>
  <i class="fas"></i>
</template>

<script>
  customElements.define('fa-button', class extends HTMLElement {
    constructor() {
      super() // returns 'this'
        .attachShadow({ mode: 'open' }) // returns AND sets 'this.shadowRoot'
        .append(document.getElementById(this.nodeName).content.cloneNode(true));
    }
    connectedCallback() {
      this.shadowRoot.querySelector("i").classList.add(this.getAttribute("icon"));
      this.onclick = () =>
        this.dispatchEvent(new CustomEvent("buttonclick", {
          detail: {
            clicked: this.getAttribute("icon")
          },
          bubbles: true,
          composed: true //escape shadowDOM
        }));
    }
  });

  document.body.addEventListener("buttonclick", (evt) => {
    console.log(evt.detail, evt.composedPath()); // full path into shadowDOM
  });

</script>

WCEVENTS

© www.soinside.com 2019 - 2024. All rights reserved.