在使用Web Components之前,我们先看看上一篇文章Web Components简介,其中提到了相关的接口、属性和方法。
正是这些接口、属性和方法才实现了Web Components的主要技术:Custom elements(自定义元素)、Shadow DOM(影子DOM)、HTML templates(HTML模板)。
由于并不是所有的接口以及接口所包含的方法都会被用到,所以我们从实际的案例出发,逐步了解Web Components的使用。
mian.js
class SearchInput extends HTMLElement {
constructor() {
super();
// 创建一个 shadow root
let shadow = this.attachShadow({mode: 'open'});
const input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('class', 'input-vlaue');
const button = document.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('value', 'Search');
// 创建一些 CSS,并应用到 shadow dom上
let style = document.createElement('style');
style.textContent=".input-vlaue{margin:5px; color:red;}";
shadow.append(input);
shadow.append(button);
shadow.append(style);
}
}
// declare var customElements: CustomElementRegistry;
customElements.define('search-input', SearchInput);
index.html
Document
这样子,一个input + button的组件就实现了。这里用到的技术有Custom elements(自定义元素)、Shadow DOM(影子DOM)。
**要注意的是,不是每一种类型的元素都可以附加到shadow root(影子根)下面。**出于安全考虑,一些元素不能使用 shadow DOM(例如),以及许多其他的元素。
Element.attachShadow() 方法给指定的元素挂载一个Shadow DOM,并且返回对 ShadowRoot 的引用。具体方法:创建一个ShadowRoot并返回它:
attachShadow(init: ShadowRootInit): ShadowRoot;
attachShadow()的参数是一个对象,里面包含两个属性,mode和delegatesFocus。
一个布尔值, 当设置为 true 时, 指定减轻自定义元素的聚焦性能问题行为.
当shadow DOM中不可聚焦的部分被点击时, 让第一个可聚焦的部分成为焦点, 并且shadow host(影子主机)将提供所有可用的 :focus 样式.
interface CustomElementRegistry {
define(name: string, constructor: CustomElementConstructor, options?: ElementDefinitionOptions): void;
get(name: string): any;
upgrade(root: Node): void;
whenDefined(name: string): Promise;
}
代码示例(index.html不变):
class SearchInput extends HTMLElement {
constructor() {
super();
// 创建一个 shadow root
let shadow = this.attachShadow({mode: 'open'});
const input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('class', 'input-vlaue');
const button = document.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('value', 'Search');
const text = document.createElement('p');
// 创建一些 CSS,并应用到 shadow dom上
let style = document.createElement('style');
style.textContent=".input-vlaue{margin:5px; color:red;}";
shadow.append(input);
shadow.append(button);
shadow.append(text);
shadow.append(style);
button.addEventListener('click', e => {
text.textContent = '按钮被点击了~'
});
}
}
// declare var customElements: CustomElementRegistry;
customElements.define('search-input', SearchInput);
main.js
class SearchInput extends HTMLElement {
constructor() {
super();
this.state = { count:0 };
// 创建一个 shadow root
let shadow = this.attachShadow({mode: 'open'});
const input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('class', 'input-value');
const button = document.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('value', 'Search');
const text = document.createElement('p');
// 创建一些 CSS,并应用到 shadow dom上
let style = document.createElement('style');
style.textContent=".input-vlaue{margin:5px; color:red;}";
shadow.append(input);
shadow.append(button);
shadow.append(text);
shadow.append(style);
button.addEventListener('click', e => {
this.state.count++;
text.textContent = `按钮被点击了${this.state.count}次。`
});
}
connectedCallback () {
const defaultValue = this.getAttribute('defaultValue');
const input = this.shadowRoot.querySelector('.input-value');
input.value = defaultValue;
}
}
// declare var customElements: CustomElementRegistry;
customElements.define('search-input', SearchInput);
index.html
Document
目前来看缺乏的就是组件间的通信了,目前还没发现有类似react、vue的组件间通信的方法,不过我们可以利用localStorage,StorageEvent间接的发生组件间的通信、界面渲染。
如果文章能够对您有所帮助,我便感到十分荣幸。如若文章能被您点赞,那便是万分荣幸。
个人微信:iotzzh
公众号:前端微说
个人网站:www.iotzzh.com