前端笔记:使⽤WebComponents进⾏原⽣组件化开发
⽂章⽬录
⽬的
前端开发中组件化开发是⼀种趋势,⽅便界⾯中各种⾃定义组件的管理与复⽤。现在流⾏的 React 和 Vue 等框架都是组件化开发的。⽬前前端原⽣也⽀持⼀定程度上的组件化开发,这个称为Web Components,这篇⽂章将对相关内容做个说明。
Web Components 是⼀套不同的技术,允许您创建可重⽤的定制元素(它们的功能封装在您的代码之外)并且在您的web应⽤中使⽤它们。
基础说明
原⽣的HTML标准中提供很多的组件,⽐如 p 、div 、button 这些,这些元素的默认样式和功能都朴素简单了,通常使⽤时我们需要根据功能需求再编写很多样式和脚本,⼤多数时候我们甚⾄需要将⼀些空间嵌套组合使⽤。这样的开发对于这些⾃⼰设计的组件的管理、维护、复⽤等⼯作都是⽐较⿇烦的。
⽐较⽅便的⼀种⽅式是所有组件相关的html和css代码都封装到js中,这样每个组件就是⼀份js代码了,
使⽤时只要调⽤相关函数将传教组件插⼊到DOM中就⾏。⽬前前端原⽣的组件化开发最根本的也是⽤js,再此基础上针对组件化需求添加了⼀些新特性。这整⼀个被称为Web Components。
Web Components主要有 四部分 三部分 组成:
原生js和js的区别Custom elements(⾃定义元素)
Shadow DOM(影⼦DOM)
HTML templates(HTML模板)
HTML Imports(HTML导⼊)
前⾯⼏部分编写的代码放⼀个html⽂件中就成了⼀个单⽂件的组件,可以使⽤HTML Imports功能在正式页⾯中导⼊组件的html⽂件来使⽤组件;这个东西现在被废弃了,⽬前还没有⾮常好的代替这个功能的东西;
技术点介绍
Custom elements
这东西就是组件化开发的核⼼了,⽤来创建⾃定义组件。这个其实很简答,创建⼀个继承⾃HTMLElement的类就⾏:
class YourComponent extends HTMLElement {
constructor(){
super();
// 组件的功能代码写在这⾥
}
}
接下来我们需要使⽤ CustomElementRegistry.define() ⽅法将上⾯的类和⼀个⾃定义的标签绑定,这样你就可以在页⾯中直接使⽤这⾥的标签来使⽤⾃定义的组件了:
customElements.define('your-component', YourComponent);
// 官⽅规定⾃定义标签必须⼤于⼀个单词,单词间⽤-连接
将两者结合⼀下就是下⾯的样⼦:
customElements.define('your-component',
class extends HTMLElement {
constructor(){
super();
// 组件的功能代码写在这⾥
}
}
);
知道上⾯两点内容后就可以创建⾃⼰的组件来使⽤了:
上图演⽰中⽤上了⾃定义的标签元素,这个内部元素内部其实就是在声明的类中⽤js代码创建的。上⾯演⽰中⾃定义组件内部的内容是在类中写死的,实际上我们希望属性是可以在使⽤时⾃由设置的。可以通过下⾯⽅式来⾃由设置属性:
除了上⾯的基础⽤法Custom elements还有⼀些⽣命周期相关的回调函数可⽤:
customElements.define('your-component',
class extends HTMLElement {
static get observedAttributes(){return['要监听的属性列表']}// 配合下⾯attributeChangedCallback()使⽤
constructor(){
super();
}
connectedCallback(){}// 当组件⾸次被插⼊⽂档DOM时被调⽤
disconnectedCallback(){}// 当组件从⽂档DOM中删除时被调⽤
adoptedCallback(){}// 当组件被移动到新的⽂档时被调⽤
attributeChangedCallback(name, oldValue, newValue){}// 当组件增加、删除、修改⾃⾝属性时被调⽤
}
);
Shadow DOM
在上⼀节其实我们已经实现了⾃定义组件,但是这⾥还存在⼀个⽐较⼤的问题。上⾯的⾃定义组件内部的各种元素对外都是可见的,这会引起很多问题,⽐如内部的元素会被外部样式所修改。这时候就要⽤到Shadow DOM了:
上⾯的 attachShadow() 中mode参数可以设置为 closed 或 open ,区别在于页⾯中JS对shadow DOM
内部元素的访问性:
HTML templates
前⾯内容中创建组件⽤的都是JS,但只⽤JS来创建组件的话组件的结构和样式稍微复杂点就变得很⿇烦了,这个时候要⽤上HTML templates了,它可以让你⽤原⽣html、css、js语⾔来编写组件。HTML templates结合前⾯的内容使⽤时差不多是下⾯这样的结构:
<template id='your-component-template'>
<!-- 这⾥编写组件的结构、样式、脚本等 -->
</template>
<script>
customElements.define('your-component',
class extends HTMLElement {
constructor(){
super();
let template = ElementById('your-component-template');
let templateContent = t;
const shadowRoot =this.attachShadow({ mode:'closed'});
shadowRoot.appendChild(templateContent.cloneNode(true));// 克隆template内部内容添加到ShadowDOM中
}
}
);
</script>
上⾯的演⽰中可以看到有了HTML templates之后编写复杂的⾃定义组件就⽅便多了。另外template中的样式中可以使⽤ :host:host()
:host-context(),⽐如下⾯这样:
:host{
/* 选择Shadow DOM本⾝ */
}
:host-context(xxx){
/* 选择Shadow DOM⽗节点,这⾥通常就是页⾯中的⾃定义标签元素本⾝了 */
}
除了上⾯的基础使⽤外HTML templates还提供了⼀个更进⼀步的功能slot。这东西可以让你在templates的html结构中插⼊⼀个插槽,这样你在使⽤⾃定义组件的时候可以向这个插槽中插⼊各种各样的东西:
如果templates中只有⼀个slot,那就可以不⽤指定name,你在⽹页上使⽤⾃定义标签之间的所有内容都会放到这个slot间。
整合成独⽴组件⽂件
上⾯演⽰中组件和页⾯都是在同⼀个⽂件中的,实际使⽤中我们通常是希望组件可以封装在独⽴的⽂件中的。
在HTML Imports弃⽤之前我们可以把组件相关的代码(⽐如template、script)这些写到⼀个html⽂件中,然后在真实页⾯头部中使⽤<link rel="import" href="your-component.html"> ⽅式引⽤组件。
在HTML Imports已经被废弃并且ES Module还⽆法import html⽂件的现在我们只能把template部分代码作为字符串嵌⼊到js代码中来使⽤了。最终组件就是⼀个独⽴的js⽂件,⽐如下⾯这样:
⽰例演⽰与说明
export default class YourComponent extends HTMLElement {
static get observedAttributes(){return['color']}
constructor(){
super();
const shadowRoot =this.attachShadow({ mode:'open'});
shadowRoot.innerHTML =`
<style>
:host {
color: ${lor};
}
</style>
<p id='text'><slot></slot></p>
`;
}
get color(){
Attribute('color')||'blue';// 如果没有设置颜⾊则返回bule作为默认颜⾊
}
set color(value){
this.setAttribute('color', value);
}
connectedCallback(){
< =ElementById('text');
}
attributeChangedCallback(name, oldValue, newValue){
if(name =='color'&&){
}
}
}
if(!('your-component')){
customElements.define('your-component', YourComponent);
}
上⾯是个简单的组件,仅仅只是控制了下⽂字的颜⾊,不过基本上展⽰出了原⽣单⽂件组件的⼀些⽤法,真正应⽤的时候更多的只是拓展组件结构,处理更多的属性。
上⾯演⽰中对于color这个属性,可以通过组件标签中添加属性来设置,也可以在页⾯上⽤CSS进⾏设置,另外虽然上⾯没有演⽰,其实也可以通过js使⽤ color(value) 或 setAttribute(name,value) ⽅法来设置。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。