前言
学习内容来源:
- https://www.youtube.com/watch?v=2I7uX8m0Ta0
- https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components
基本概念
- Custom element(自定义元素):class或者function,定义组件api
- Shadow DOM(影子 DOM):用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)。使元素私有化,样式不会相互干扰。
- HTML template(HTML 模板):
<template>
和<slot>
可以编写不在呈现页面中显示的标记模板。
调试
谷歌浏览器:设置——preferences——Elements——Show user agent shadow DOM打钩
自定义组件
- 注册组件
// TodoItem.js
class TodoItem extends HTMLElement{}
customElements.define("todo-item", TodoItem) // 传入组件名称与组件
<todo-item></todo-item>
- 创建模板
// TodoItem.js
const template=document.createElement("template")
template.innerHTML=`
<style>
label{
display: block;
}
.description{
color: #a9a9a9;
font-size: .8em;
}
</style>
<label>
<input type="checkbox" />
<slot></slot>
<span class="description">
<slot name="description"></slot>
</span>
</label>
`
- 打开shadow dom
// TodoItem.js
class TodoItem extends HTMLElement{
constructor(){
super()
// ++ 打开shadow dom
const shadowDom = this.attachShadow({ mode : "open"})
// ++ 将模板克隆进去
shadowDom.appendChild(template.content.cloneNode(true))
}
}
<todo-item>
<!--内容会加到默认slot中 -->
todo1
<!--内容会加到description slot中 -->
<span slot="description">其他描述</span>
</todo-item>
- 生命周期
// TodoItem.js
class TodoItem extends HTMLElement{
constructor(){
super()
const shadowDom = this.attachShadow({ mode : "open"})
shadowDom.appendChild(template.content.cloneNode(true))
}
// ++ 自定义元素挂载时被调用
connectedCallback() {}
// ++ 自定义元素卸载时被调用
disconnectedCallback() {}
}
内置元素扩展-可展开列表
- 注册组件:继承ul标签
// ExpandableList.js
class ExpandableList extends HTMLUListElement {}
customElements.define('expandable-list', ExpandableList, {
extends: 'ul',
});
- 定义组件
class ExpandableList extends HTMLUListElement {
constructor() {
super();
this.style.position = 'relative';
// 创建一个子元素
this.toggleBtn = document.createElement('button');
this.toggleBtn.style.position = 'absolute';
this.toggleBtn.style.border = 'none';
this.toggleBtn.style.background = 'none';
this.toggleBtn.style.padding = 0;
this.toggleBtn.style.top = 0;
this.toggleBtn.style.left = '5px';
this.toggleBtn.style.cursor = 'pointer';
this.toggleBtn.innerText = '>';
this.appendChild(this.toggleBtn);
// 定义点击事件
this.toggleBtn.addEventListener('click', () => {
this.dataset.expanded = !this.isExpanded;
});
}
// 计算属性
get isExpanded() {
return (
this.dataset.expanded !== 'false' && this.dataset.expanded !== null
);
}
// 监听属性
static get observedAttributes() {
return ['data-expanded'];
}
// 监听到上方属性变化后调用
attributeChangedCallback(name, oldValue, newValue) {
this.updateStyles();
}
updateStyles() {
const transform = this.isExpanded ? 'rotate(90deg)' : '';
this.toggleBtn.style.transform = transform;
[...this.children].forEach((child) => {
if (child !== this.toggleBtn) {
child.style.display = this.isExpanded ? '' : 'none';
}
});
}
// 挂载后调用
connectedCallback() {
this.updateStyles();
}
}
customElements.define('expandable-list', ExpandableList, {
extends: 'ul',
});
- 使用:通过is传入扩展
<ul is="expandable-list" data-expanded>
<li>apple</li>
<li>banana</li>
</ul>
标签:Web,style,TodoItem,示例,Component,toggleBtn,extends,template,class
From: https://www.cnblogs.com/sanhuamao/p/17587646.html