addEventListener 在自定义元素中不起作用
addEventListener not working in custom element
我正在为我的网站制作一个大富翁游戏,我遇到了一个问题,我无法为自定义元素中的 "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:添加事件原型:
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
的最新版本
感谢 @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>
`;
}
}
一些建议:
ShadowDOM 中的
FontAwesome 和 Bootstrap CSS 也 需要在主文档中加载 CSS
对于 shadowDOM 中的单击,您不必使用事件 Listener(用于添加多个侦听器的技术),设置 onclick
事件 处理程序 会做
使用 <TEMPLATE>
而不是使用 JS 创建 HTML 更不容易出错(而且更简单,代码更少,并且..)
使用 dispatchEvent 发出您自己的 CustomEvent
,使您免于处理 path[0]
全局事件监听器中的数据
注意:CSS 在此 SO 片段中加载会导致点击后 3 秒的延迟...仅在 Whosebug
<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>
我正在为我的网站制作一个大富翁游戏,我遇到了一个问题,我无法为自定义元素中的 "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:添加事件原型:
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
的最新版本感谢 @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>
`;
}
}
一些建议:
ShadowDOM 中的
FontAwesome 和 Bootstrap CSS 也 需要在主文档中加载 CSS
对于 shadowDOM 中的单击,您不必使用事件 Listener(用于添加多个侦听器的技术),设置
onclick
事件 处理程序 会做使用
<TEMPLATE>
而不是使用 JS 创建 HTML 更不容易出错(而且更简单,代码更少,并且..)使用 dispatchEvent 发出您自己的
CustomEvent
,使您免于处理path[0]
全局事件监听器中的数据
注意:CSS 在此 SO 片段中加载会导致点击后 3 秒的延迟...仅在 Whosebug
<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>