从Web组件内部访问html标签



我正在学习js web组件的第一个概念。我在这些方面很在行,并试图做一个简单的例子。我的组件只是一个假装改变颜色为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>

这是我的组件:

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

是可能的web组件以这种方式工作吗?

关于发布的代码有一些注意事项:

CSS,shadowDOM

.container{
display: flex;
flex-direction: column;
align-items: center;
}
.hi-button{
margin-top: 10px;
}
这个<<p> strong>全球CSS从来不应用于元素shadowDOM内的HTML。

注意,你不必使用shadowDOM。

<<ul>
  • 模板/gh>
  • 自定义元素API
  • shadowDOM
  • are 3distinct可以独立使用的技术。

    要应用该样式,请在中声明它shadowDOM:
    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>

    点击事件默认情况下,按钮上的click事件会弹出DOM。

    不需要在<button>本身上设置处理程序,您可以在任何父节点上设置。

    垃圾收集

    无需删除内部/上的监听器定制元素。JavaScript垃圾收集进程会为你做这些

    当您在其他DOM元素上设置侦听器时,需要removelistener。
    。当组件在document上设置监听器

    disabledCallback

    不存在;它叫做disconnectedCallback()

    作曲= true

    this.dispatchEvent(new CustomEvent("button-clicked", { 
    bubbles: true,
    }));
    

    这只适用于事件是而不是从shadowDOM调度。

    但是从shadowDOM内部调度,或者使用shadowDOM将元素包装在另一个元素中并且代码将不再工作,因为默认情况下,Custom Events不'escape' shadowDOM(s)。

    为此,您需要使用:

    this.dispatchEvent(new CustomEvent("button-clicked", { 
    bubbles: true,
    composed: true
    }));
    

    默认注意:类似clickdo的事件

    解决方案没有
    >唯一需要的代码是:
    • 全局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>

    与shadowDOM

    • 不太需要CSS类,因为所有的HTML都被隔离在shadowDOM

    • <template>可以被声明为HTML(所以你的IDE整齐地格式化里面的一切)由this.nodeName引用,所以你可以重用代码

    • super()&attachShadow()函数设置返回this范围和this.shadowRoot;所以它们可以被链接

    • 自定义事件是伟大的;但这段代码可以使用默认的click事件;侦听器检查是否单击了正确的按钮

    • 这些只是Web组件的技术增强,加载更多的功能增强可能,所有取决于用例

    • 在继续<slot>内容之前,请先读取::slot CSS选择器用于shadowDOM槽中嵌套的子节点

    代码可以看something这样的:

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

    维护组件间独立性的最好方法是使用events

    Web组件分派一个由父容器侦听的事件。然后,父节点执行必要的操作。

    如果你想"直接"在组件和父组件之间,系统是耦合的,这不是一个好方法。当然可以,但不推荐。

    你可以检查这个更清楚的答案。

    还有,用事件回答你的问题。就像这样简单:

    首先,在你的组件中,你必须以这种方式分派事件:

    this.dispatchEvent(new CustomEvent("button-clicked", { 
    bubbles: true,
    }));
    

    你可以在这里查看这个的用法。

    同样,父进程将使用:

    document.addEventListener("button-clicked", changeColor);
    

    因此,当按钮被单击时,父级将触发changeColor函数,其中包含您想要的逻辑。

    通过这种方式,你使用Web组件对父容器执行操作,但系统没有耦合。父母可以在没有孩子的情况下工作,孩子也可以在没有父母的情况下工作。两者都可以单独使用。当然,事件不会被调度或监听,但是组件之间没有依赖关系。

    这是一个如何工作的例子。

    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>

    最新更新