Web Components 入门实例教程

1、自定义元素

2、customElements.define()
class UserCard extends HTMLElement {
constructor() {
super();
}
}
window.customElements.define('user-card', UserCard);
3、自定义元素的内容
class UserCard extends HTMLElement {
constructor() {
super();
var image = document.createElement('img');
image.src = '';
image.classList.add('image');
var container = document.createElement('div');
container.classList.add('container');
var name = document.createElement('p');
name.classList.add('name');
name.innerText = 'User Name';
var email = document.createElement('p');
email.classList.add('email');
email.innerText = 'yourmail@some-email.com';
var button = document.createElement('button');
button.classList.add('button');
button.innerText = 'Follow';
container.append(name, email, button);
this.append(image, container);
}
}
4、标签使用JavaScript写上一级的DOM结构很麻烦,Web Components API提供了标签,可以在它里面使用HTML定义的DOM。
User Name
yourmail@some-email.com
然后,改写一下自定义元素的类,为自定义元素加载。
class UserCard extends HTMLElement {
constructor() {
super();
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
this.appendChild(content);
}
}
上面的代码中,获取上游以后,克隆了它的所有子元素,这是因为可能有多个自定义元素的实例,这个模板还要留给其他实例使用,所以不能直接移动它的子元素。到这一步为止,完整的代码如下。
...
5、添加样式
自定义元素还没有样式,可以给它指定细分样式,类似下面这样。
user-card {
/* ... */
}
但是,组件的样式应该与代码封装在一起,只对自定义元素实施,不影响外部的布局样式。所以,可以把样式写在里面。
:host {
display: flex;
align-items: center;
width: 450px;
height: 180px;
background-color: #d4d4d4;
border: 1px solid #d5d5d5;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 3px;
overflow: hidden;
padding: 10px;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
.image {
flex: 0 0 auto;
width: 160px;
height: 160px;
vertical-align: middle;
border-radius: 5px;
}
.container {
box-sizing: border-box;
padding: 20px;
height: 160px;
}
.container > .name {
font-size: 20px;
font-weight: 600;
line-height: 1;
margin: 0;
margin-bottom: 5px;
}
.container > .email {
font-size: 12px;
opacity: 0.75;
line-height: 1;
margin: 0;
margin-bottom: 15px;
}
.container > .button {
padding: 10px 25px;
font-size: 12px;
border-radius: 5px;
text-transform: uppercase;
}
User Name
yourmail@some-email.com
上方代码中,样式里面的:host伪类,指代自定义元素本身。6、自定义元素的参数
内容现在是在里面设定的,为了方便使用,把它改成参数。
image=""
name="User Name"
email="yourmail@some-email.com"
>
代码也相应改造。
最后,改一下类的代码,把参数加到自定义元素里面。
class UserCard extends HTMLElement {
constructor() {
super();
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
content.querySelector('img').setAttribute('src', this.getAttribute('image'));
content.querySelector('.container>.name').innerText = this.getAttribute('name');
content.querySelector('.container>.email').innerText = this.getAttribute('email');
this.appendChild(content);
}
}
window.customElements.define('user-card', UserCard);
7、影子DOM
我们不希望用户能够看到的内部代码,Web组件允许内部代码隐藏起来,这叫做Shadow DOM,即这部分DOM默认与外部DOM隔离,内部任何代码都无法影响外部。 自定义元素的this.attachShadow()方法开启Shadow DOM,详见下面的代码。
class UserCard extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow( { mode: 'closed' } );
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
content.querySelector('img').setAttribute('src', this.getAttribute('image'));
content.querySelector('.container>.name').innerText = this.getAttribute('name');
content.querySelector('.container>.email').innerText = this.getAttribute('email');
shadow.appendChild(content);
}
}
window.customElements.define('user-card', UserCard);
上面的代码中,this.attachShadow()方法的参数{ mode: 'closed' },表示Shadow DOM是封闭的,永久外部访问。 至此,这个Web组件组件就完成了,完整代码可以访问这里。可以看到,整个过程还是很简单的,不像第三方框架那样有复杂的API。 8、组件的扩展
在前面的基础上,可以对组件进行扩展。 (1)与用户互动 用户卡片是一个静态组件,如果要与用户互动,也很简单,就是在类里面监听各种事件。
this.$button = shadow.querySelector('button');
this.$button.addEventListener('click', () => {
// do something
});
(2)组件的封装 上面的例子中,与网页代码放在一起,可以其实用脚本把注入|网页。这样的话,JavaScript的跟脚本就能封装一个分类中翻译JS文件,成为独立的组件文件。网页只要加载这个脚本,使用就能组件。这里就不展开了,更多Web Components的高级用法,可以接着学习下面两篇文章。 Web组件初学者教程 自定义元素v1:可重用的Web组件
九,参考链接
Web组件剖析,Uday Hiwarale
(完)

浏览
1评论
User Name
yourmail@some-email.com
class UserCard extends HTMLElement {
constructor() {
super();
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
this.appendChild(content);
}
}
...
5、添加样式
user-card {
/* ... */
}
:host {
display: flex;
align-items: center;
width: 450px;
height: 180px;
background-color: #d4d4d4;
border: 1px solid #d5d5d5;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 3px;
overflow: hidden;
padding: 10px;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
.image {
flex: 0 0 auto;
width: 160px;
height: 160px;
vertical-align: middle;
border-radius: 5px;
}
.container {
box-sizing: border-box;
padding: 20px;
height: 160px;
}
.container > .name {
font-size: 20px;
font-weight: 600;
line-height: 1;
margin: 0;
margin-bottom: 5px;
}
.container > .email {
font-size: 12px;
opacity: 0.75;
line-height: 1;
margin: 0;
margin-bottom: 15px;
}
.container > .button {
padding: 10px 25px;
font-size: 12px;
border-radius: 5px;
text-transform: uppercase;
}
User Name
yourmail@some-email.com
6、自定义元素的参数
image=""
name="User Name"
email="yourmail@some-email.com"
>
class UserCard extends HTMLElement {
constructor() {
super();
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
content.querySelector('img').setAttribute('src', this.getAttribute('image'));
content.querySelector('.container>.name').innerText = this.getAttribute('name');
content.querySelector('.container>.email').innerText = this.getAttribute('email');
this.appendChild(content);
}
}
window.customElements.define('user-card', UserCard);
7、影子DOM
class UserCard extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow( { mode: 'closed' } );
var templateElem = document.getElementById('userCardTemplate');
var content = templateElem.content.cloneNode(true);
content.querySelector('img').setAttribute('src', this.getAttribute('image'));
content.querySelector('.container>.name').innerText = this.getAttribute('name');
content.querySelector('.container>.email').innerText = this.getAttribute('email');
shadow.appendChild(content);
}
}
window.customElements.define('user-card', UserCard);
8、组件的扩展
this.$button = shadow.querySelector('button');
this.$button.addEventListener('click', () => {
// do something
});
Web组件初学者教程 自定义元素v1:可重用的Web组件
九,参考链接
Web组件剖析,Uday Hiwarale

评论