我正在学习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>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
}));
默认注意:类似click
do的事件
- 全局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>