优点
- 可以通过shadowDOM实现css隔离
- 原生的组件化开发
Custom elements
- 继承自 HTMLElement 抽象类的自主自定义标签
- 继承自内建的HTML元素的自定义内建元素
提示:Custom element 名称必须包括一个短横线 -,这是为了保证和内建html元素标签不冲突
自主自定义标签
class MyElement extends HTMLElement {
constructor() {
super();
// 元素在这里创建
}
connectedCallback() {
// 在元素被添加到文档之后,浏览器会调用这个方法
//(如果一个元素被反复添加到文档/移除文档,那么这个方法会被多次调用)
}
disconnectedCallback() {
// 在元素从文档移除的时候,浏览器会调用这个方法
// (如果一个元素被反复添加到文档/移除文档,那么这个方法会被多次调用)
}
static get observedAttributes() {
return [/* 属性数组,这些属性的变化会被监视 */];
}
attributeChangedCallback(name, oldValue, newValue) {
// 当上面数组中的属性发生变化的时候,这个方法会被调用
}
}
// 注册元素
customElements.define("my-element", MyElement);
自定义内建元素
class HelloButton extends HTMLButtonElement { /* custom element 方法 */ }
// 使用时通过<button is="hello-button"></button>来展示
customElements.define('hello-button', HelloButton, {extends: 'button'});
Template
- 本身被视为超出文档结构的的范围,不会对文档产生影响,可以用做webcomponent的html结构
- 内部可以增加style标签来写样式
Shadow DOM
ele.attachShadow({ mode: 'open/close' });
如果mode设置为true,则可以使用elem.shadowRoot来获取shadowDOM 的root节点,否则只能用attachShadow方法返回值来获取
Shadow DOM slot
占槽元素来自 light DOM,所以它们使用文档样式。局部样式不会影响占槽内容, 可以使用slot[name=xxx]或::slotted(xxx) 来设置
// 自主自定义标签
const template = document.createElement('template');
template.innerHTML = `
<style>
::slotted(span) {
color: blue;
}
</style>
<div>
<slot name="inner"></slot>
</div>
`;
class CustromElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
console.log(template.content);
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('custom-element', CustromElement);
Shadow DOM Event
当事件在组件外部捕获时,shadow DOM 中发生的事件将会以 host 元素作为目标。
事件仅仅是在它们的 composed 标志设置为 true 的时候才能通过 shadow DOM 边界。
触发自定义事件
// 自定义事件
element.dispatchEvent(new CustomEvent('test', {
bubbles: true,
composed: true,
// 通过detail属性传递数据
detail: "composed"
}));
将DOM结构、样式写在同一个文件
const template = document.createElement('template');
template.innerHTML = `
<style>
.container {
padding: 8px;
}
button {
display: block;
overflow: hidden;
position: relative;
padding: 0 16px;
font-size: 16px;
font-weight: bold;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
outline: none;
width: 100%;
height: 40px;
box-sizing: border-box;
border: 1px solid #a1a1a1;
background: #ffffff;
box-shadow: 0 2px 4px 0 rgba(0,0,0, 0.05), 0 2px 8px 0 rgba(161,161,161, 0.4);
color: #363636;
}
</style>
<div class="container">
<button>Label</button>
</div>
`;
class Button extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.appendChild(template.content.cloneNode(true));
}
}
window.customElements.define('my-button', Button);
·