Web-Components 定义,使用以及示例
1. 定义
web-componets 类似于vue以及react中组件定制,将一组ui以及公共逻辑抽取,并且封装成为一个公共组件。在页面可以随处调用
2. 实现web component的基本方法
a. 创建一个类或函数来指定web组件的功能
class Dialog extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const p = document.createElement('p');
const text = this.getAttribute('dialog-text');
p.textContent = text;
shadow.appendChild(p);
}
}
b. 用 customElements.define() 方法注册自定义的元素 ,并且指定component名称,以及创建的类。
customElements.define('dialog-element', Dialog);
c. 在页面中使用
d. 页面显示
4. 生命周期
connectedCallback- 当 custom element首次被插入文档DOM时,被调用
disconnectedCallback- 当 custom element从文档DOM中删除时,被调用
adoptedCallback- 当 custom element被移动到新的文档时,被调用
attributeChangedCallback- 当 custom element增加、删除、修改自身属性时,被调用
- 生命周期使用实例
class Dialog extends HTMLElement {
constructor() {
super();
}
static get observedAttributes() {
return ['dialog-text'];
}
connectedCallback() {
console.log('dialog element added to page.');
}
disconnectedCallback() {
console.log('dialog element removed from page.');
}
adoptedCallback() {
console.log('dialog element moved to new page.');
}
attributeChangedCallback(name, oldValue, newValue) {
console.log('dialog element attributes changed.');
}
}
5. window.customElements属性
- customElements.define
- 定义:定义一个自定义元素
- 语法:
customElements.define(name, constructor, options); - 参数:
- name:自定义元素名,所创建的元素名称的符合 DOMString 标准的字符串。注意,custom element 的名称不能是单个单词,且其中必须要有短横线
- constructor: 自定义元素的构造类
- options:控制元素如何定义 . 目前有一个选项支持
- extends. 指定继承的已创建的元素. 被用于创建自定义元素.
示例
// customElements.define('dialog-element', Dialog);
// customElements.define('dialog-element', Dialog, { extends: 'div' });
// customElements.define('dialog-element', class extends HTMLElement {});
- customElements.get
- 定义:返回以前定义自定义元素的构造函数,如果获取不到,则返回undefined
- 语法:
const constructor = customElements.get(name); - 参数:
- name: 自定义元素的名字
示例
const constructor = customElements.get('dialog-element');
console.log(constructor, `constructor`);
// class Dialog {}
- customElements.whenDefined
- 定义:当一个元素被定义时,返回一个promise,当获取到自定义元素时,立即resolve,当元素名称不是一个有效名称时,则立即执行rejecte
- 语法:
customElements.whenDefined(name) - 参数:
- name: 自定义元素的名字
class Dialog extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const p = document.createElement('p');
p.textContent = 'this is dialog element';
shadow.appendChild(p);
}
}
customElements.define('dialog-element', Dialog);
customElements.whenDefined('dialog-element').then(() => {
console.log(`dialog-element is defined`);
});
customElements
.whenDefined('aaa')
.then(() => {
console.log(`dialog-element is defined`);
})
.catch(err => {
console.log(err, `err`);
// Failed to execute 'whenDefined' on 'CustomElementRegistry': "aaa" is not a valid custom element name
});
6. custom elements类别
Autonomous custom elements- 说明:Autonomous custom elements 是独立的元素,可以直接在body内使用,例如
,或者js创建document.createElement("task-list")
- 说明:Autonomous custom elements 是独立的元素,可以直接在body内使用,例如
Customized built-in elements- 说明:Customized built-in elements 继承自基本的HTML元素。在创建时,必须指定继承的元素,也就是
{ extends: 'div' },在body中使用,js创建document.createElement('ul',{ is:'task-list' })
- 说明:Customized built-in elements 继承自基本的HTML元素。在创建时,必须指定继承的元素,也就是
7. 定义Autonomous custom elements组件
- 使用shadow root外部样式影响不到组件
class TaskList extends HTMLElement {
constructor() {
super();
// 这里的this就是task-list元素
// 创建一个shadow root
const shadow = this.attachShadow({ mode: 'open' });
// 通过getAttribute方法获取标签上的属性
const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
// 创建一个ul元素
const ul = document.createElement('ul');
ul.classList.add('task-list');
// 循环创建li元素
dataList.forEach(item => {
const li = document.createElement('li');
li.classList.add('task-item');
li.textContent = item;
li.addEventListener('click', this.showItemContent.bind(this, li));
ul.appendChild(li);
});
// 创建样式
const style = document.createElement('style');
style.textContent = this.defineStyle();
// 将样式添加至shadow 根节点
shadow.appendChild(style);
// 将ul添加至shadow 根节点
shadow.appendChild(ul);
}
/**
* 定义组件样式,外部style无法影响组件样式
*/
defineStyle() {
return `
.task-list{
list-style: none;
}
`;
}
showItemContent(ele) {
console.log(ele.textContent, `ele.textContent`);
}
}
// 定义task-list组件
customElements.define('task-list', TaskList);
页面显示
- 不使用shadow root 外部样式可以影响组件
class TaskList extends HTMLElement {
constructor() {
super();
// 这里的this就是task-list元素
// 通过getAttribute方法获取标签上的属性
const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
// 创建一个ul元素
const ul = document.createElement('ul');
ul.classList.add('task-list');
// 循环创建li元素
dataList.forEach(item => {
const li = document.createElement('li');
li.classList.add('task-item');
li.textContent = item;
li.addEventListener('click', this.showItemContent.bind(this, li));
ul.appendChild(li);
});
// 将ul添加至根节点
this.appendChild(ul);
}
showItemContent(ele) {
console.log(ele.textContent, `ele.textContent`);
}
}
// 定义task-list组件
customElements.define('task-list', TaskList);
页面展示
8. 定义Customized built-in elements组件
class TaskList extends HTMLUListElement {
constructor() {
super();
// 这里的this就是task-list元素
this.classList.add('task-list');
// 通过getAttribute方法获取标签上的属性
const dataList = JSON.parse(this.getAttribute('data-list') || '[]');
// 循环创建li元素
dataList.forEach(item => {
const li = document.createElement('li');
li.classList.add('task-item');
li.textContent = item;
this.appendChild(li);
});
}
}
// 定义task list组件,必须定义{ extends: 'ul' },否则会报错
// Illegal constructor: autonomous custom elements must extend HTMLElement
customElements.define('task-list', TaskList, { extends: 'ul' });
页面展示
9. 定义组件的方式
- template方式
- 1
- 2
customElements.define(
'task-list',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('task-list');
let templateContent = template.content;
// 使用cloneNode方式将templateContent添加到当前元素中
this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
}
}
);
页面展示
10. 插槽的使用
1
- 2
base item
this is slot content
customElements.define(
'task-list',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('task-list');
let templateContent = template.content;
// 使用cloneNode方式将templateContent添加到当前元素中
this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
}
}
);
页面展示
11. webcomponets示例之notify组件
webcomponets示例之notify组件