Web Components
原因
探讨使用Web Components的原因,我们已经知道像 Vue 和 React 这样的成熟框架存在,但是有没有深入思考过为什么选择使用这些框架?核心理由无非是为了减少编码工作量,通过框架减少代码重复,尽管这同时引入了一些原生不支持的特性,从而增加了一定的复杂性。当我了解到Web Components时,我开始思考是否可以用它来取代 Vue,因为 Vue 的主要优势之一就是能够实现组件的封装和复用
构成
Web Components 由三个主要部分构成,与Vue的模板非常相似:
- 自定义元素(Custom Element): 这是一组JavaScript API,使你能够定义自定义元素及其行为,以便根据需要在用户界面中使用它们
- 影子DOM(Shadow DOM): 这也是一组JavaScript API,用于将一个封闭的“影子”DOM树附加到元素上(与主文档DOM分开渲染),并管理其相关功能。这样,你可以确保元素的功能是私有的,因此它们可以被脚本化和样式化,而不会与文档的其他部分产生冲突
- HTML模板(HTML Template): template 和 slot 元素让你能够创建不会立即显示在渲染页面中的标记模板。然后,这些模板可以作为自定义元素结构的基础,被反复使用
使用
接下来说一下 Web Components 的基本使用~
自定义组件
创建一个基础的自定义组件包含以下步骤:
- 1、继承: 自定义元素需要通过继承HTMLElement类(或其子类)来创建
- 2、创建模板: 使用document.createElement('template')来创建一个新的模板元素
- 3、获取影子DOM: 通过元素的attachShadow方法获取影子DOM,为元素提供封装的DOM结构
- 4、添加内容: 将模板内容通过appendChild方法添加到影子DOM中。使用cloneNode方法克隆节点,避免对原始模板的污染。
- 5、定义组件: 使用customElements.define('component-tag-name', ComponentClassName)来定义组件,使其可在页面中使用
至此,一个最基础的自定义组件创建完成
图片
拓展点:
- 在最初阶段,我尝试通过WebComponent.html的形式编写自定义组件,这样可以直接在标签中写样式和HTML,便于编辑器提供代码提示和格式化。然而,由于当前标签不支持直接导入HTML文件,除非通过HTTP GET请求加载外部HTML,但这种方法似乎违背了初衷。
- 要监听属性的变化,必须通过static get observedAttributes静态方法声明哪些属性是被监听的。之后,就可以在attributeChangedCallback回调函数中捕获属性变化。
- 自定义元素也拥有简化的生命周期钩子,虽然只有三个,但它们的存在使得状态管理变得简单。
- 支持使用插槽(slots),类似于Vue,可以通过的方式来实现内容的插入。
在html中使用
- 当引入自定义组件时,建议使用defer属性,这样可以确保脚本在文档解析完成后再执行,避免潜在的执行顺序问题。自定义组件的标签使用方式与Vue非常相似,即使用组件在define时指定的名称,并通过slot="slot-name"来指定插槽的名称。在Vue项目中,可以通过简单地导入组件的JavaScript文件(例如import "./components/WebComponent/WebComponent.js";)来使用这些自定义元素。
图片
在实际使用中,可能会遇到一些挑战:
- 通常情况下,自定义组件内部和父组件都会包含一些业务逻辑,这可能需要父组件向子组件暴露某些方法。例如,在自定义组件被加入到页面(即在connectedCallback被调用)之后,可能需要通知父组件,这时可以通过调用在父组件中定义的this.ready()方法。为了避免connectedCallback在ready方法定义之前执行而导致错误,推荐在引入自定义组件的脚本标签中加上defer
- 若需调用自定义组件的方法,必须确保自定义组件已经完全创建好。因此,在示例中通过定义一个ready方法,并在connectedCallback调用之后执行它,或者等待页面的onload事件触发后执行。这意味着定义和调用之间的执行顺序需要特别注意,以避免由于执行顺序引起的问
- 监听属性变化时,应使用setAttribute方法来修改属性值,因为直接修改属性(如extendP.attributes['size']=200)不会触发属性监听回调
- 关于插槽(slot)传值的问题,目前似乎没有直接的方法来实现
简而言之,虽然自定义组件的使用看似简单直接,但在实际开发中还是需要注意脚本加载顺序、组件通信和属性监听等细节问题,以确保组件能够正确无误地运行
参考文章:https://juejin.cn/post/7309693162368565299