使用原生 JavaScript 实现组件化开发

说明

我们将通过实现一个名为 custom-card 的组件来展示如何使用浏览器提供的 customElements API 来创建自定义元素。


自定义组件详解

1. 创建组件

要创建一个自定义组件,需要继承 HTMLElement 类,并实现其功能。我们还将使用 Shadow DOM 来隔离组件内部的结构和样式。

⚠️ 注意:Shadow DOM 并不是所有元素都能添加(例如 <img> 标签无法添加伪类),这点需要注意。

js 复制代码
class CustomCard extends HTMLElement {
  constructor() {
    super();
    // 创建 Shadow DOM
    this.attachShadow({ mode: 'open' });
    
    // 获取模板并克隆插入到 Shadow DOM 中
    const template = document.querySelector('#custom-card-template');
    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }
}

// 注册组件
customElements.define('custom-card', CustomCard);

2. 准备组件模板

我们使用 <template> 标签来存放组件的 HTML 模板。该标签默认不会渲染在页面上,但可以通过 JavaScript 访问其中的内容。

在样式部分,:host 是一个伪类选择器,用于选中 Shadow DOM 的根节点,即组件本身。

html 复制代码
<template id="custom-card-template">
  <style>
    :host {
      border: 1px solid #ccc;
      box-shadow: 0 2px 4px #ccc;
    }
    .card-head {
      border-bottom: 1px solid #ccc;
      padding: 6px 8px;
    }
    .card-foot {
      padding: 6px 8px;
      border-top: 1px solid #ccc;
    }
  </style>
  <div class="card-wraaper">
    <div class="card-head">
      <slot name="head">这是头部</slot>
    </div>
    <div class="card-body">
      <slot>这是中间的内容</slot>
    </div>
  </div>
</template>

3. 使用组件

在 HTML 页面中直接使用自定义标签 <custom-card> 即可:

  • 具名插槽(Named Slot) :通过 slot="xxx" 将内容插入指定名称的插槽。
  • 默认插槽(Default Slot) :未命名的内容将插入默认插槽。
  • 如果没有提供对应插槽的内容,则显示模板中的默认内容。
html 复制代码
<custom-card>
  <div slot="head">卡片1</div>
  <div>这是中间的内容1</div>
  <div>这是中间的内容2</div>
  <div>这是中间的内容3</div>
</custom-card>

补充知识与总结

以下是一些扩展知识点,帮助你更好地理解和使用 Web Components 技术。

组件生命周期方法

在定义组件类时,可以重写以下生命周期钩子函数:

方法名 触发时机
connectedCallback() 当组件被插入文档时调用
disconnectedCallback() 当组件从文档中移除时调用
attributeChangedCallback(attrName, oldVal, newVal) 当组件属性发生变化时调用(需配合 observedAttributes

📌 提示:如果希望监听某些属性的变化,必须在类中定义静态属性 observedAttributes,返回一个包含这些属性名的数组。


HTML 相关知识

  1. <template>:语义为模板,不直接渲染,常用于存储可重复使用的 HTML 片段。
  2. <slot>:插槽机制,允许外部传入内容填充组件模板。
  3. part标签属性:用于 Shadow DOM 中标记特定部分,可通过 CSS 选择器访问。
  4. is="custom-element"标签属性:可以在原生标签中使用自定义组件的行为。

CSS 相关知识

选择器 功能说明
::slotted() 选择插槽中的内容,如 ::slotted(.card-head)
:host 选择 Shadow DOM 的根节点
:defined 选择已经定义的自定义元素
::part(name) 选择具有 part="name" 的 Shadow DOM 子元素

JavaScript 相关知识

  1. window.customElements:用于注册自定义元素。
  2. Element.attachShadow():创建一个隔离的 Shadow DOM 结构,实现样式和 DOM 隔离。

与 Vue 等框架是否冲突?

可能会有人担心:使用 Web Components 是否会与 Vue、React 等框架产生冲突或难以辨识?

实际上,Vue 等框架在构建阶段会将组件编译成普通的 HTML 标签和 render 函数,最终生成的是标准的 DOM 元素。浏览器接收到的是标准标签,因此 Web Components 和框架之间并不会冲突。

如果你感兴趣,可以阅读官方文档了解更多信息: 🔗Vue 与 Web Components | Vue.js


总结

通过本文,你应该已经掌握了:

  • 如何使用原生 JavaScript 创建自定义组件;
  • 如何利用 Shadow DOM 实现样式和结构的封装;
  • 插槽机制的基本使用;
  • 生命周期方法的作用;
  • 以及 Web Components 与主流框架之间的兼容性问题。

加油,虽然是用不太上的知识点!

相关推荐
lyj16899711 分钟前
vue-i18n+vscode+vue 多语言使用
前端·vue.js·vscode
小白变怪兽2 小时前
一、react18+项目初始化(vite)
前端·react.js
ai小鬼头2 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
墨菲安全3 小时前
NPM组件 betsson 等窃取主机敏感信息
前端·npm·node.js·软件供应链安全·主机信息窃取·npm组件投毒
GISer_Jing3 小时前
Monorepo+Pnpm+Turborepo
前端·javascript·ecmascript
天涯学馆3 小时前
前端开发也能用 WebAssembly?这些场景超实用!
前端·javascript·面试
我在北京coding4 小时前
TypeError: Cannot read properties of undefined (reading ‘queryComponents‘)
前端·javascript·vue.js
前端开发与ui设计的老司机4 小时前
UI前端与数字孪生结合实践探索:智慧物流的货物追踪与配送优化
前端·ui
全能打工人4 小时前
前端查询条件加密传输方案(SM2加解密)
前端·sm2前端加密
翻滚吧键盘5 小时前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js