语义化 HTML 编写一个原生 Web Components 组件

简介: 使用语义化 HTML 编写一个原生 Web Components 组件

如果需要设计编写一个组件用以将内容隐藏在一个警告栏后面,你会想到怎么做呢?今天我就用语义化的 HTML 结合 CSS 来完成这一组件,这也意味着无论在 ReactVue 中都可以插入,不过它俩可不是今天的主角,接下来我将介绍如何封装一个原生 HTMLWeb Components 组件,让我们开始吧!

HTML结构

首先我们来了解下 HTML 中的 <details> 元素,它可以用于创建一个小部件,其中包含仅在小部件处于“打开”状态时才可见的附加信息,<details>元素内可以包含的内容没有任何限制。

默认情况下,元素创建的小部件 <details>处于“关闭”状态( open标签可使其打开)。通过单击小部件在“打开”和“关闭”状态之间切换,以显示或隐藏标签中包含的附加信息,内部标签 <summary> 元素则可为该部件提供概要。

一个简单的例子如下:

<details>
    <summary> 不能说的秘密 </summary>
    藏的这么深,可还是被你发现了
</details>
details {
    border: 1px solid #aaa;
    border-radius: 4px;
    padding: .5em .5em 0;
}

summary {
    font-weight: bold;
    margin: -.5em -.5em 0;
    padding: .5em;
}

details[open] {
    padding: .5em;
}

details[open] summary {
    border-bottom: 1px solid #aaa;
    margin-bottom: .5em;
}

2022-09-12 11.16.09.gif

使用语义化 HTML 的优点:页面内容结构更清晰,方便开发者阅读,更利于浏览器的理解与加载,搜索引擎解析与SEO优化。

添加亿点样式

原生元素默认的样式很简陋,因此我们需要为其定制一下样式,这块内容我们简单带过,只讲解关键部分,样式内容有省略,具体可以在文末的码上掘金中看到呈现效果。

.ContentWarning > summary {
  position: relative;
  list-style: none; /** 去除默认样式 **/
  user-select: none; 
  cursor: pointer;
  /** 为其添加一个斜线背景 **/
  --stripe-color: rgb(0 0 0 / 0.1);
  background-image: repeating-linear-gradient(45deg,
      transparent,
      transparent 0.5em,
      var(--stripe-color) 0.5em,
      var(--stripe-color) 1em);
}

/** 通过var变量调整悬停时的颜色样式 **/
.ContentWarning>summary: hover,
.ContentWarning>summary: focus {
  --stripe-color: rgb(150 0 0 / 0.1);
}

2022-09-12 15.19.27.gif

封装模板

现在我们来把它封装成一个完整的组件,这需要先将 HTML 编写在模板 template 当中,并设置一个 id,如下所示:

<template id="warning-card">  
  <details class="ContentWarning">
    <summary>
      <strong>⚠️ 注意:</strong> 以下为隐藏内容
    </summary>
    <slot name="desc"> 藏的这么深,可还是被你发现了 </slot>
  </details>
</template>

熟悉 Vue 的小伙伴应该很容易理解上面的代码,结构很相似,不过网页不会直接渲染它包裹的内容。此外我们还对此模板设置了一个插槽 slot,后面会讲到它的作用。

定义组件

有了上面封装好的模板,我们就需要在 JS 中定义成可用组件来让其能够被使用,调用 window 下的 customElements.define 方法,第一个参数是传入组件名称,我们定义组件名为: warning-card ,第二个参数传入一个继承了 HTMLElement 的类,在其构造方法当中获取并克隆一个新的 HTML 节点,它会通过 appendChild 渲染到页面当中。

window.customElements.define('warning-card',
  class extends HTMLElement {
    constructor() {
      super();
      var templateElem = document.getElementById('warning-card');
      var content = templateElem.content.cloneNode(true);
      this.appendChild(content);
    }
  })

接着我们就可以在页面中把它当作组件那样使用了:

<warning-card> </warning-card>

插槽与传参

回头看看上面我们模板中设置的插槽 slot,此时还是没有生效的,我们需要稍微改写一下构造函数中的渲染方式,将 web 组件定义为一个 Shadow DOM,这样构造的是一个可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起的独立元素,并在最后使用 Node.cloneNode() 方法添加了模板的拷贝到 Shadow 的根结点上。

window.customElements.define('warning-card',
  class extends HTMLElement {
    constructor() {
      super();
      var template = document.getElementById('warning-card').content;
      this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
    }
  })

现在我们尝试使用下组件,往其内容添加一个图片,指向名为 descslot 插槽中:

<warning-card>
  <img slot="desc" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ba825ffee78c4a1b9c0232e5d2f1d048~tplv-k3u1fbpfcp-watermark.image?" />
</warning-card>

这时你会发现,图片插入到 details 元素的隐藏区域当中了,slot 已经成功生效,但是样式却消失了,这时因为组件已经被完全隔离,我们需要将样式作用在其内部才会生效。

<template id="warning-card">
  <style>
    <!-- TODO: 组件的样式 -->
  </style>
  
  <details class="ContentWarning">
    <summary>
      <strong>⚠️ 注意:</strong>
    </summary>
    <slot name="desc">THE DESCRIPTION</slot>
  </details>
</template>

这样组件就正常了:

2022-09-12 15.45.07.gif

除了定制模板中的插槽,我们也可以通过 HTML 标签属性来实现一些简单的传参,例如在 summary 标签中显示一个标题:

<warning-card title="前方高能">
</warning-card>

我们只需要在模板中定义好这个标题的位置:

<template id="warning-card">
  <details class="ContentWarning">
    <summary>
        <!-- TODO: 模板中加入一个span标签 -->
      <strong>⚠️ 注意:</strong> <span id="title"></span>
    </summary>
  </details>
</template>

最后在构造函数中我们通过 document 的原生方法写入模板中就可以了:

window.customElements.define('warning-card',
  class extends HTMLElement {
    constructor() {
      super();
      var template = document.getElementById('warning-card').content;
      // TODO: 找到title标签,写入传入组件的title属性值
      template.querySelector('#title').innerText = this.getAttribute('title');
      this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
    }
  })

结束

至此,我们通过编写一个简单的原生组件学习了如何编写 Web Components,可以在下面的码上掘金中查看全部具体的源码:

代码片段

[](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ba825ffee78c4a1b9c0232e5d2f1d048~tplv-k3u1fbpfcp-watermark.image?)

如果觉得文章对你有帮助,希望多多点赞支持!也欢迎关注,我会持续更新前端有用的知识与实用技巧,共同成长。

相关文章
|
25天前
|
存储 Web App开发 移动开发
HTML5 Web 存储详解
HTML5 Web存储提供了两种客户端数据存储机制:**Local Storage**和**Session Storage**。Local Storage用于长期存储数据,即使关闭浏览器数据也依然存在,适用于保存用户偏好设置等信息。Session Storage则在标签或窗口关闭时清除数据,适合存储临时信息。两者均提供了简单的API进行数据的存取操作,但需要注意的是,Web存储并非加密存储,不应存放敏感信息。现代浏览器普遍支持Web存储,合理利用这两种存储方式可提升Web应用的用户体验。
|
23天前
|
存储 移动开发 大数据
HTML5 Web IndexedDB 数据库详解
IndexedDB 是一种高效的浏览器存储方案,允许在本地存储大量结构化数据,支持索引和事务,适用于需要离线和大数据处理的应用。它由数据库、对象仓库等组成,通过键值对存储数据,确保数据一致性和完整性。本介绍展示了如何创建、读取、更新和删除数据,以及事务和错误处理的最佳实践。
|
1月前
|
数据可视化 前端开发
Twaver-HTML5基础学习(39)鹰眼可视化视图组件(OverView)
本文介绍了如何在Twaver-HTML5中使用鹰眼(Overview)可视化视图组件,它作为Network的缩略图,允许用户通过缩略图导航Network,支持单击、双击和框选操作来控制Network视图。
34 5
Twaver-HTML5基础学习(39)鹰眼可视化视图组件(OverView)
|
8天前
|
前端开发 JavaScript 开发者
Web组件:一种新的前端开发范式
【10月更文挑战第9天】Web组件:一种新的前端开发范式
11 2
|
1月前
|
数据可视化 前端开发 容器
Twaver-HTML5基础学习(41)列表可视化视图组件(List)
本文介绍了如何在Twaver-HTML5中使用列表可视化视图组件(List),展示了如何创建列表、设置列表属性(如行高、间隔颜色等)、实现数据绑定和排序,以及如何通过React代码示例进行操作。
20 2
Twaver-HTML5基础学习(41)列表可视化视图组件(List)
|
16天前
|
前端开发 JavaScript Go
前端开发趋势:从响应式设计到Web组件的探索
【10月更文挑战第1天】前端开发趋势:从响应式设计到Web组件的探索
28 3
|
23天前
|
存储 移动开发 数据库
HTML5 Web IndexedDB 数据库常用数据存储类型
IndexedDB 支持多种数据存储类型,满足复杂数据结构的存储需求。它包括基本数据类型(如 Number、String、Boolean、Date)、对象(简单和嵌套对象)、数组、Blob(用于二进制数据如图像和视频)、ArrayBuffer 和 Typed Arrays(处理二进制数据)、结构化克隆(支持 Map 和 Set 等复杂对象),以及 JSON 数据。尽管不直接支持非序列化数据(如函数和 DOM 节点),但可以通过转换实现存储。开发者应根据具体需求选择合适的数据类型,以优化性能和使用体验。
|
19天前
|
移动开发 JavaScript 前端开发
HTML5 Web Workers详解
HTML5 Web Workers 允许在后台线程中运行 JavaScript,实现复杂计算而不影响用户界面,提升应用性能。其主要特性包括并行处理、异步通信、独立作用域及多数据类型支持。通过创建和使用 Worker 文件,如 `worker.js`,可执行后台任务,并与主线程通过消息传递机制通信。适用于数据处理、图像处理、复杂计算及网络请求并行等场景。需要注意的是,Web Workers 在浏览器兼容性、安全性限制、调试及资源消耗方面需特别关注。合理利用 Web Workers 可显著增强 Web 应用的流畅度和响应速度。
|
24天前
|
SQL 存储 移动开发
HTML5 Web SQL 数据库详解
Web SQL 数据库是 HTML5 中的一种本地存储技术,允许在浏览器中使用 SQL 语言操作本地数据,支持离线访问和事务处理,适用于缓存数据和小型应用。然而,其存储容量有限且仅部分现代浏览器支持,标准已不再积极维护,未来可能被 IndexedDB 和 localStorage 等技术取代。使用时需谨慎考虑兼容性和发展前景。
|
24天前
|
存储 移动开发 缓存
HTML5 Web 存储详解
HTML5 Web 存储包括 `localStorage` 和 `sessionStorage`,前者提供持久存储且无过期时间,后者仅在会话期间有效。两者均支持键值对形式存储数据,容量约为 5-10 MB。`localStorage` 适用于用户偏好设置、登录状态保持及离线应用缓存;`sessionStorage` 则用于临时数据如表单输入。数据以字符串形式存储,可通过 `JSON` 方法处理对象。由于数据存储于本地,不适合存放敏感信息。示例代码展示了如何使用按钮将输入框内容保存至 `localStorage` 并进行清除操作。