你不知道的web component系列——改造Vite模版实现一个自定义元素 你将会收获1. 对web compon
你不知道的web component系列——改造Vite模版实现一个自定义元素
注: 本文属于你不知道的web component系列的前置部分, 旨在帮助开发者更好的了解web component,渐进式的深入web component这一浏览器特性!
前言
web component早在数十年前就已经作为浏览器的新特性被讨论和应用, 它旨在解决下面的开发痛点:
- 一个页面中不同的公用组件之间样式的侵扰,经常在我们需要开发一个页面新功能时,却被别的样式影响导致我们需要反复的修改和覆盖.
- 页面中其它元素绑定的事件会影响到我要开发的功能,我们需要去调查究竟是哪一点影响到了,十分影响开发进度和体验.
- 当不使用开发框架开发时, 我们所要考虑的问题复杂度急剧升高, 开发不规范问题会导致代码新功能的添加、错误的排查等等难度陡然升高.
本文就将会基于这些痛点, 以vite为工具,以改造vite提供的模版来实现并打包一个web component,读完本文你将会获得:
- 对web component的更深入的理解,真正理解web component的三大技术核心——自定义元素
- 基于web component的OOP式开发思维
初始化模版
本文使用的版本信息如下: create-vite@5.5.2 vite/5.4.2将会基于这些版本来改动最终实现一个web component 版本的Vite template, 下面是步骤:
- 执行命令: npm create vite, 按照步骤选择others -> create-vite-extra
- Select a template这里选择 : library -> typescript
- 切换到改目录下后, 安装相关依赖
最终我们会得到这样一个文件夹:
开始——自定义元素
首先, 什么是自定元素, 要搞清楚这个我们就需要了解什么叫做元素(这同时会引出什么叫做语义化元素)!所谓的元素是针对html文本而言, 它组成了整个html骨架,不妨来列举一些常见的元素,比如:html,body,div,span, header…这些都是我们常见的元素, 它们有着自己的元素样式, 逻辑,名字等, 而自定义元素就是定义一个特殊的元素(包括元素: 名字,样式,逻辑)下面我们尝试修改一下vite模版提供给我们的代码实现一个我们自定义的元素吧!我们来实操一下试试: 首先打开src/main.ts文件, 我们尝试添加一个自定义元素hello world如下:
就这样, 我们很轻松的就实现了一个我们自定义的元素: hello world, 细心的朋友肯定会发现这个元素css上会有一个继承自HTML元素, 是的默认我们这样直接编写的它会继承HTMLElement的逻辑,样式等等,那么还有没有别的办法定义一个不继承HTML元素的样式逻辑呀?
用js实现自定义元素
下面我们会使用javascript中的类式编程来实现一个不继承html元素(基类)的wc-vite, 同时也会用到浏览器专门提供给我们的一个api接口Window.customElements 的 define() 方法, 如下:
// 下面是用js实现的独立自定义元素:
class WcVite2 extends HTMLElement {
constructor () {
super()
this.innerHTML = 'Hello World2'
}
}
customElements.define('wc-vite2', WcVite2)
// 使用如下:
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
<img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
</a>
<h1>Vite + TypeScript</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the Vite and TypeScript logos to learn more
</p>
</div>
<h1 is="wc-vite"></h1>
<wc-vite2></wc-vite2>
`
基于上面我们的实现, 让我们来总结一下: 自定义元素式指: 由 Web 开发人员定义行为的 HTML 元素,扩展了浏览器中可用的元素集, 我们开发人员可以实现的两种自定义元素:
- 自定义内置元素(Customized built-in element)继承自标准的 HTML 元素,例如 HTMLImageElement 或 HTMLParagraphElement。它们的实现定义了标准元素的行为。
- 独立自定义元素(Autonomous custom element)继承自 HTML 元素基类 HTMLElement。你必须从头开始实现它们的行为。
此外我们使用自定义元素的方式:
- 直接在页面中使用我们自定义标签,形如: 或者自定义内置元素
- 使用js创建并插入到页面中去(下文我们将会使用)
自定义元素的生命周期
观察前面我们写的代码, 我们用类定义的元素所有的操作都是在构造器中, 这样做的好处就是简洁方便, 可是当我们的需求发生改变时直接写在构造器中会让我们的代码变的难以维护,并且它只会执行一次,这就要引出我们自定义元素的生命周期回调:
- connectedCallback():每当元素添加到文档中时调用。规范建议开发人员尽可能在此回调中实现自定义元素的设定,而不是在构造函数中实现。
- disconnectedCallback():每当元素从文档中移除时调用。
- adoptedCallback():每当元素被移动到新文档中时调用。
- attributeChangedCallback():在属性更改、添加、移除或替换时调用。有关此回调的更多详细信息,请参见响应属性变化。 我们来改造一下我们写过的这两种自定义元素, 如下:
// 用js实现的自定义元素
class WcVite extends HTMLHeadingElement {
static observedAttributes = ["color", "size"];
constructor() {
super()
}
connectedCallback() {
console.log("自定义元素添加至页面。");
this.innerHTML = 'Hello World1'
}
disconnectedCallback() {
console.log("自定义元素从页面中移除。");
// 其它代码
}
adoptedCallback() {
console.log("自定义元素移动至新页面。");
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(`属性 ${name} 已变更。`);
}
//别的属性/方法...
}
customElements.define('wc-vite', WcVite, {extends: 'h1'})
// 下面是用js实现的独立自定义元素:
class WcVite2 extends HTMLElement {
constructor () {
super()
}
connectedCallback() {
console.log("自定义元素添加至页面。");
this.innerHTML = 'Hello World2'
}
disconnectedCallback() {
console.log("自定义元素从页面中移除。");
// 其它代码
}
adoptedCallback() {
console.log("自定义元素移动至新页面。");
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(`属性 ${name} 已变更。`);
}
//别的属性/方法...
}
customElements.define('wc-vite2', WcVite2)
// 使用如下.....
👍恭喜你, 你已经完全掌握了如何在浏览器中实现一个自定义元素!
实现一个ViteApp自定义元素
通过观察我们发现,ViteApp也是一个被插入到页面中的元素,它上面除了有着自定义的样式和元素外,还有着一定的逻辑,我们接下来试着用到上面所掌握的web component的自定义元素技巧,封装一个随处可用的自定义元素!!!
class ViteApp extends HTMLElement {
constructor () {
super()
}
connectedCallback () {
console.log('始化了');
this.innerHTML = `
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
<img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
</a>
<h1>Vite + TypeScript</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the Vite and TypeScript logos to learn more
</p>
</div>
`
// 初始化逻辑
setupCounter(this.querySelector<HTMLButtonElement>('#counter')!)
}
}
customElements.define('vite-app', ViteApp)
const viteapp = document.createElement('vite-app')
document.querySelector<HTMLDivElement>('#app')!.append(viteapp)
效果如下:
最终, 我们就实现一个封装完成的ViteApp组件,并且它可以在页面中任何地方使用!
总结
通过本文, 我们了解到了自定义元素的概念和分类, 我们动手实现了两种自定义元素并渲染到了页面上, 在文章最后我们实现了一个自定义的ViteApp组件,并且通过类式编程我们实现了它的逻辑隔离.
但是, 它的样式仍然会被影响, 下一章我们将会引入另外一个特性——shadowDom, 我们同样会基于vite模版去介绍这个特性,让你更加深入的理解web component.未完,待续.......
转载自:https://juejin.cn/post/7408138735797534758