JavaScript(Ts) 初试使用 Web Components 开发一个 dialog 组件
关于
Web Components
Vite
为工程依赖
Ts
语言开发
<!-- index.html -->
<body>
<button class="open">open</button>
<my-dialog>
<h1>wo cao nb</h1>
</my-dialog>
<script type="module" src="./src/index.ts"></script>
</body>
/* ./src/index.ts */
class MyDialog extends HTMLElement {
static componentName: string = 'my-dialog'
private closeButton: HTMLButtonElement;
constructor() {
super();
const style = `
:host(:not([open])) {
display: none;
}
:host {
position: fixed;
left: 0; top: 0;
height: 100%; width: 100%;
background-color: rgba(25, 28, 34, 0.88);
z-index: 19;
display: grid;
place-items: center;
}
dialog {
position: static;
display: inherit;
}
`
const html = `
<style>${style}</style>
<dialog>
<!-- slot 插槽 作用与 Vue 的 slot 相同-->
<slot>暂无提示信息</slot>
<p>
<button name="close">确定</button>
</p>
</dialog>
`
// 解析html 字符串
const template = document.createRange().createContextualFragment(html)
const shadowRoot = this.attachShadow({mode: "open"})
shadowRoot.append(template)
this.closeButton = this.shadowRoot.querySelector('button[name="close"]')
this.closeButton.addEventListener('click', this.hide.bind(this))
}
hide() {
this.toggleAttribute('open', false)
}
// 连接到 DOM
connectedCallback() {
/**
* 一种常见错误是将 connectedCallback 用做一次性的初始化事件,
* 然而实际上你每次将节点连接到 DOM 时都会被调用。
* 取而代之的,
* 在 constructor 这个 API 接口调用时做一次性初始化工作会更加合适。
*/
}
// 从 DOM 上脱离
disconnectedCallback() {
this.closeButton.removeEventListener('click', this.hide.bind(this))
}
}
window.customElements.define(MyDialog.componentName, MyDialog)
const onLoaded = () => {
const $ = {
open: document.querySelector('.open'),
dialog: document.querySelector('my-dialog')
}
$.open.addEventListener('click', () => {
$.dialog.toggleAttribute('open', true)
})
}
window.addEventListener('load', onLoaded)
为之则易,不为则难。