从 Web 组件内部访问 html 标签
Access to html tag from inside Web Components
我正在学习 js 网络组件的初步概念。我对这些很感兴趣,并尝试做一个简单的例子。我的组件只是一个假装将颜色更改为 div.
的按钮
我的示例工作符合我的预期,但我注意到我的方法不是太多的“组件方式”,如果我尝试更改的元素在我的 Web 组件中而不是在它之外。
这是我的 html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<my-component></my-component>
</div>
<script src="myComponent.js"></script>
</body>
</html>
这是我的组件.js:
const template = `
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.box{
width: 100px;
height: 100px;
background: red;
}
.hi-button{
margin-top: 10px;
}
</style>
<div class="container">
<div class="box"></div>
<button class="hi-button">Change</button>
</div>
`;
class MyFirstTest extends HTMLElement{
constructor(){
super()
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = template;
}
changeButtonColor(){
const box = this.shadowRoot.querySelector(".box");
if(box.style.background === 'red'){
box.style.background = 'blue';
}else{
box.style.background = 'red';
}
}
connectedCallback(){
const event = this.shadowRoot.querySelector(".hi-button");
event.addEventListener('click', () => this.changeButtonColor());
}
disabledCallback(){
const event = this.shadowRoot.querySelector(".button-test");
event.removeEventListener();
}
}
customElements.define('my-component', MyFirstTest);
正如我所说,功能运行良好,但我不希望我的 div 出现在我的 Web 组件中,而是出现在我的 html 文件中,并且mi组件只是按钮。
例如,我的 html 文件是这样的:
.......
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="my-div-to-change"></div>
<my-component></my-component>
</div>
</body>
.......
网络组件可以这样工作吗?
保持组件之间独立性的最好方法是使用events
。
Web 组件调度由 parent 容器侦听的事件。然后,parent 执行必要的操作。
如果你想在组件和 parent 之间“直接”对话,系统耦合度很高,不是一个好方法。当然可以,但不推荐。
您可以查看答案,哪个更清楚。
此外,使用事件回答您的问题。就这么简单:
首先,在您的组件中,您必须以这种方式分派事件:
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
你可以检查here这个的用法。
此外,parent 将使用以下方式收听:
document.addEventListener("button-clicked", changeColor);
因此,当单击按钮时,parent 将触发函数 changeColor
,其中包含您想要的逻辑。
通过这种方式,您可以使用 Web 组件对 parent 容器执行操作,但系统并未耦合。 Parent 可以在没有 child 的情况下工作,child 可以在没有 parent 的情况下工作。两者都可以单独使用。当然,事件不会被派发或监听,但组件之间没有依赖关系。
这也是它如何工作的一个例子。
const template = `
<div class="container">
<button class="hi-button">Change</button>
</div>
`;
class MyFirstTest extends HTMLElement{
constructor(){
super()
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = template;
}
changeButtonColor(){
//Call parent
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
}
connectedCallback(){
const event = this.shadowRoot.querySelector(".hi-button");
event.addEventListener('click', () => this.changeButtonColor());
}
disabledCallback(){
const event = this.shadowRoot.querySelector(".button-test");
event.removeEventListener();
}
}
customElements.define('my-component', MyFirstTest);
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.box{
width: 100px;
height: 100px;
background: red;
}
.hi-button{
margin-top: 10px;
}
</style>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="box"></div>
<my-component></my-component>
</div>
<script src="myComponent.js"></script>
<script>
//Add listener to do the action
document.addEventListener("button-clicked", changeColor);
function changeColor(){
var box = document.querySelector(".box");
if(box.style.backgroundColor === 'red'){
box.style.backgroundColor = 'blue';
}else{
box.style.backgroundColor = 'red';
}
}
</script>
</body>
</html>
发布的代码有一些注意事项:
CSS & 阴影DOM
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.hi-button{
margin-top: 10px;
}
此 global CSS 永远不会应用于元素阴影 HTML 内 DOM.
请注意,您不必使用影子DOM。
- 模板
- 自定义元素API
- 阴影DOM
有 3 种不同的 技术,您可以单独使用它们。
要应用样式,请在阴影内部声明它DOM:
const template = `
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.hi-button{
margin-top: 10px;
}
</style>
<div class="container">
<button class="hi-button">Change</button>
</div>
模板
它只是一个字符串,您没有使用或声明 <template>
点击事件
按钮上的点击事件,默认情况下,弹出 DOM。
无需在 <button>
本身上设置处理程序,您可以在任何父级上设置。
垃圾回收
无需删除监听器 inside/on 自定义元素。 JavaScript 垃圾收集 进程会为您做这件事
在其他 DOM 元素上设置监听器时,需要移除监听器。
例如。当组件在 document
上设置监听器时
禁用回调
不存在;它叫做 disconnectedCallback()
组合 = 真
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
这只有效,因为事件不是从影子DOM调度的。
但是从 shadowDOM 内部调度,或者用 shadowDOM 将元素包裹在另一个元素中,代码将不再有效,因为 Custom默认情况下,事件不会 'escape' shadowDOM(s).
为此,您需要使用:
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
composed: true
}));
注意:默认 像click
do escape shadowDOM这样的事件默认
解决方案
没有阴影DOM唯一需要的代码是:
- 全局 CSS 现在设置按钮样式
customElements.define('my-component', class MyFirstTest extends HTMLElement {
connectedCallback() {
this.innerHTML = `<button class="hi-button">Change</button>`;
this.onclick = (evt) => document.querySelector(".box").classList.toggle("blue");
}
});
<style>
.box {
width: 80px;
height: 80px;
background: red;
}
.blue {
background: blue;
}
.hi-button {
margin-top: 10px;
}
</style>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="box"></div>
<my-component></my-component>
</div>
有阴影DOM
不需要CSS类,因为所有HTML都被隔离在阴影DOM
<template>
可以 声明为 HTML(所以你的 IDE 可以整齐地格式化里面的所有内容)由 this.nodeName
,所以你可以重复使用代码
super()
&attachShadow()
是函数设置和返回 this
范围和 this.shadowRoot
;所以他们可以被链接起来
自定义事件很棒;但是这段代码可以处理默认的 click
事件;侦听器检查是否单击了正确的按钮
这些只是 Web Component 技术增强,加载更多功能增强可能,完全取决于用例
在继续阅读 <slot>
内容之前请先阅读
代码可能看起来类似:
<template id="MY-COMPONENT">
<style>
div { display: flex; flex-direction: column; align-items: center }
button { margin-top: 10px }
</style>
<div>
<button><slot></slot></button>
</div>
</template>
<div class="main">
<my-component color="blue">Blue!</my-component>
<my-component color="gold">Gold!</my-component>
<my-component color="rebeccapurple">Purple!</my-component>
</div>
<script>
document.addEventListener("click", (evt) => {
if (evt.target.nodeName == 'MY-COMPONENT')
document.querySelector(".main").style.background = evt.target.getAttribute("color");
});
customElements.define('my-component', class extends HTMLElement {
constructor() {
let template = (id) => document.getElementById(id).content.cloneNode(true)
super()
.attachShadow({mode: 'open' })
.append( template(this.nodeName) );
}
});
</script>
我正在学习 js 网络组件的初步概念。我对这些很感兴趣,并尝试做一个简单的例子。我的组件只是一个假装将颜色更改为 div.
的按钮我的示例工作符合我的预期,但我注意到我的方法不是太多的“组件方式”,如果我尝试更改的元素在我的 Web 组件中而不是在它之外。
这是我的 html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<my-component></my-component>
</div>
<script src="myComponent.js"></script>
</body>
</html>
这是我的组件.js:
const template = `
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.box{
width: 100px;
height: 100px;
background: red;
}
.hi-button{
margin-top: 10px;
}
</style>
<div class="container">
<div class="box"></div>
<button class="hi-button">Change</button>
</div>
`;
class MyFirstTest extends HTMLElement{
constructor(){
super()
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = template;
}
changeButtonColor(){
const box = this.shadowRoot.querySelector(".box");
if(box.style.background === 'red'){
box.style.background = 'blue';
}else{
box.style.background = 'red';
}
}
connectedCallback(){
const event = this.shadowRoot.querySelector(".hi-button");
event.addEventListener('click', () => this.changeButtonColor());
}
disabledCallback(){
const event = this.shadowRoot.querySelector(".button-test");
event.removeEventListener();
}
}
customElements.define('my-component', MyFirstTest);
正如我所说,功能运行良好,但我不希望我的 div 出现在我的 Web 组件中,而是出现在我的 html 文件中,并且mi组件只是按钮。
例如,我的 html 文件是这样的:
.......
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="my-div-to-change"></div>
<my-component></my-component>
</div>
</body>
.......
网络组件可以这样工作吗?
保持组件之间独立性的最好方法是使用events
。
Web 组件调度由 parent 容器侦听的事件。然后,parent 执行必要的操作。
如果你想在组件和 parent 之间“直接”对话,系统耦合度很高,不是一个好方法。当然可以,但不推荐。
您可以查看
此外,使用事件回答您的问题。就这么简单:
首先,在您的组件中,您必须以这种方式分派事件:
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
你可以检查here这个的用法。
此外,parent 将使用以下方式收听:
document.addEventListener("button-clicked", changeColor);
因此,当单击按钮时,parent 将触发函数 changeColor
,其中包含您想要的逻辑。
通过这种方式,您可以使用 Web 组件对 parent 容器执行操作,但系统并未耦合。 Parent 可以在没有 child 的情况下工作,child 可以在没有 parent 的情况下工作。两者都可以单独使用。当然,事件不会被派发或监听,但组件之间没有依赖关系。
这也是它如何工作的一个例子。
const template = `
<div class="container">
<button class="hi-button">Change</button>
</div>
`;
class MyFirstTest extends HTMLElement{
constructor(){
super()
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = template;
}
changeButtonColor(){
//Call parent
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
}
connectedCallback(){
const event = this.shadowRoot.querySelector(".hi-button");
event.addEventListener('click', () => this.changeButtonColor());
}
disabledCallback(){
const event = this.shadowRoot.querySelector(".button-test");
event.removeEventListener();
}
}
customElements.define('my-component', MyFirstTest);
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.box{
width: 100px;
height: 100px;
background: red;
}
.hi-button{
margin-top: 10px;
}
</style>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="box"></div>
<my-component></my-component>
</div>
<script src="myComponent.js"></script>
<script>
//Add listener to do the action
document.addEventListener("button-clicked", changeColor);
function changeColor(){
var box = document.querySelector(".box");
if(box.style.backgroundColor === 'red'){
box.style.backgroundColor = 'blue';
}else{
box.style.backgroundColor = 'red';
}
}
</script>
</body>
</html>
发布的代码有一些注意事项:
CSS & 阴影DOM
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.hi-button{
margin-top: 10px;
}
此 global CSS 永远不会应用于元素阴影 HTML 内 DOM.
请注意,您不必使用影子DOM。
- 模板
- 自定义元素API
- 阴影DOM
有 3 种不同的 技术,您可以单独使用它们。
要应用样式,请在阴影内部声明它DOM:
const template = `
<style>
.container{
display: flex;
flex-direction: column;
align-items: center;
}
.hi-button{
margin-top: 10px;
}
</style>
<div class="container">
<button class="hi-button">Change</button>
</div>
模板
它只是一个字符串,您没有使用或声明 <template>
点击事件
按钮上的点击事件,默认情况下,弹出 DOM。
无需在 <button>
本身上设置处理程序,您可以在任何父级上设置。
垃圾回收
无需删除监听器 inside/on 自定义元素。 JavaScript 垃圾收集 进程会为您做这件事
在其他 DOM 元素上设置监听器时,需要移除监听器。
例如。当组件在 document
禁用回调
不存在;它叫做 disconnectedCallback()
组合 = 真
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
}));
这只有效,因为事件不是从影子DOM调度的。
但是从 shadowDOM 内部调度,或者用 shadowDOM 将元素包裹在另一个元素中,代码将不再有效,因为 Custom默认情况下,事件不会 'escape' shadowDOM(s).
为此,您需要使用:
this.dispatchEvent(new CustomEvent("button-clicked", {
bubbles: true,
composed: true
}));
注意:默认 像click
do escape shadowDOM这样的事件默认
解决方案
没有阴影DOM唯一需要的代码是:
- 全局 CSS 现在设置按钮样式
customElements.define('my-component', class MyFirstTest extends HTMLElement {
connectedCallback() {
this.innerHTML = `<button class="hi-button">Change</button>`;
this.onclick = (evt) => document.querySelector(".box").classList.toggle("blue");
}
});
<style>
.box {
width: 80px;
height: 80px;
background: red;
}
.blue {
background: blue;
}
.hi-button {
margin-top: 10px;
}
</style>
<div class="main">
<h1>Yeah Web Components!</h1>
<div class="box"></div>
<my-component></my-component>
</div>
有阴影DOM
不需要CSS类,因为所有HTML都被隔离在阴影DOM
<template>
可以 声明为 HTML(所以你的 IDE 可以整齐地格式化里面的所有内容)由this.nodeName
,所以你可以重复使用代码super()
&attachShadow()
是函数设置和返回this
范围和this.shadowRoot
;所以他们可以被链接起来自定义事件很棒;但是这段代码可以处理默认的
click
事件;侦听器检查是否单击了正确的按钮这些只是 Web Component 技术增强,加载更多功能增强可能,完全取决于用例
在继续阅读
<slot>
内容之前请先阅读
代码可能看起来类似:
<template id="MY-COMPONENT">
<style>
div { display: flex; flex-direction: column; align-items: center }
button { margin-top: 10px }
</style>
<div>
<button><slot></slot></button>
</div>
</template>
<div class="main">
<my-component color="blue">Blue!</my-component>
<my-component color="gold">Gold!</my-component>
<my-component color="rebeccapurple">Purple!</my-component>
</div>
<script>
document.addEventListener("click", (evt) => {
if (evt.target.nodeName == 'MY-COMPONENT')
document.querySelector(".main").style.background = evt.target.getAttribute("color");
});
customElements.define('my-component', class extends HTMLElement {
constructor() {
let template = (id) => document.getElementById(id).content.cloneNode(true)
super()
.attachShadow({mode: 'open' })
.append( template(this.nodeName) );
}
});
</script>