使用原生 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 与主流框架之间的兼容性问题。

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

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.6 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~7 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华8 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子10 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅10 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学12 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端