Web Components,启动!

大家好,这里是大家的林语冰。坚持阅读,自律打卡,每天一次,进步一点

免责声明

本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 Getting into web components – an intro

本期共享的是 —— 今年对于 WC(Web Components,Web 组件)而言兹事体大,本人对此感到鸡冻。说实话,不久前本人对 WC 几乎一无所知,因为私以为 WC 只是网络上不值一提的蜉蝣之物。但 WC 正在引起更多话题。所以我想更多地了解 WC。

Web Components,启动!

WC 是什么鬼物?

WC 就像网站的构建块,甚至可能是构建块组。

我们可以自定义元素,比如 <my-button><for-love>,而不是循规蹈矩地使用 <div><button> 等标准标签。自定义元素代表我们可以在网站或网络 App 中使用和重用的独特组件。自定义元素内部始终需要有一个连字符,用来区分其与标准 HTML 元素,并遵循 WC 规范设置的命名约定。

连字符背后的主要原因是为了避免冲突,减少与标准 HTML 元素发生命名冲突的机会。由于标准 HTML 元素不包含连字符(当然,现在永远不会包含连字符)。

Shadow DOM

Shadow DOM 就像一个 Web 元素的“密室”。假设我们有一个工作区,我们正在其中构建网站的不同部分。某些部分需要在不影响其余部分的情况下完成工作。Shadow DOM 提供了一个封装的空间来实现这一点。这个“密室”内的元素可以有自己的样式、脚本和结构,而不会干扰主页或其他元素的样式和脚本。我们所指的其他元素就是我们所说的“Light DOM”。

<div>
  <p>This is content outside the Shadow DOM, thus "Light DOM".</p>
  <my-element></my-element>
</div>

<script>
  // 创建一个新的自定义元素
  class MyElement extends HTMLElement {
    constructor() {
      super()

      // 为自定义元素创建 Shadow DOM
      const shadow = this.attachShadow({ mode: 'open' })

      // 在 Shadow DOM 里创建 p 标签
      const paragraph = document.createElement('p')
      paragraph.textContent = 'Shadow DOM 里的内容'

      // 将 p 标签添加到 Shadow DOM
      shadow.appendChild(paragraph)
    }
  }

  // 定义自定义元素
  customElements.define('my-element', MyElement)
</script>

Shadow DOM 有某些具体的特征:

封装:在 Shadow DOM 里,我们的样式和脚本不会受到外界的影响。此行为有助于防止样式意外与网页上其他元素混淆。除了自定义属性之外,外部 CSS 不会对其产生任何影响。

组合:Shadow DOM 引入了插槽,即迷你占位符,我们可以在其中插入自定义内容。这意味着,我们可以自定义元素的内部,而不会破坏原始设计。

举个栗子,我们将在 WC 内插入 <h2><p>。它唯一要做的就是,在它们之间放置一个 <hr>

<my-card>
  <!-- Content placed inside the slots -->
  <h2 slot="title">Card Title</h2>
  <p slot="content">This is the content of the card.</p>
</my-card>

<script>
  class MyCard extends HTMLElement {
    constructor() {
      super()

      // 为自定义元素创建 Shadow DOM
      const shadow = this.attachShadow({ mode: 'open' })

      // 为卡片内容创建容器
      const cardContainer = document.createElement('div')

      // 为标题创建插槽
      cardContainer.innerHTML = `
          <slot name="title"></slot>
          <hr>
          <slot name="content"></slot>
        `

      // 将卡片容器添加到 Shadow DOM
      shadow.appendChild(cardContainer)
    }
  }

  customElements.define('my-card', MyCard)
</script>

现在想象一下 JS 失败了,页面仍然会显示 WC 内部提供的插槽内容,因为这只是一些轻量级 DOM,唯一缺少的是 <hr>。即使我们必须支持不支持此功能的浏览器,它仍然可能是一个渐进增强。

可访性:可访问性是一种共享语言。Shadow DOM 里的元素可以理解并使用与外部元素相同的辅助语言。更重要的是,它确实可以辅助我们处理某些更难访问的用例,比如选项卡。

关注点分离:Shadow DOM 可让我们将结构、样式和行为整齐地排列在各自的分区中。想象一下,拥有一个用于所有这些重复任务的 WC 库:可访问的选项卡、图像缩放和可动画的下拉菜单。我们仍然可以使用自定义属性来设置样式,因为这些属性会渗透到 WC 中。

::part 伪元素:它允许我们从 Shadow DOM 外部设置 WC 的特定命名部分的样式。

举个栗子:

<my-element>
  <h2 slot="header">头部内容</h2>
  <p slot="content">主内容</p>
</my-element>

这就是我们的 WC 的样子(粉丝请注意 innerHTML 的属性):

class MyElement extends HTMLElement {
  constructor() {
    super()
    const shadow = this.attachShadow({ mode: 'open' })
    shadow.innerHTML = `
	    <style>
            div {
            border: 3px solid blue;
            }
        </style>

        <div part="header"><slot name="header"></slot></div>
        <hr/>
        <div part="content"><slot name="content"></slot></div>
    `
  }
}

customElements.define('my-element', MyElement)

现在解释这一点的最好方法是用边框将其可视化。默认情况下,影子 DOM 内的 <div> 元素具有蓝色边框。我们想要为包裹标题槽的 <div> 提供绿色边框,我们可以访问它:

/* h2 默认样式 */
h2 {
  margin-block: 30px;
  color: red;
  border: 3px solid red;
}

/* 头部的绿色边框 */
my-element::part(header) {
  border: 3px solid green;
}

WC 的开发体验

像这样编写 WC 并不是一种很好的开发人员体验……至少在我看来。对于基本示例而言,它似乎工作得很好,但我只是喜欢编辑器中的一些结构和颜色,而不是仅仅将每个输出放入字符串中。

我们可以使用 Lit 库来辅助创建 WC。Lit 库旨在使 WC 的使用更轻松高效。它提供了若干优点,只需以正常方式编写它们就可以减轻一些负担。

Lit 提供了一种更具声明性的语法来定义组件。使用此方法可以使我们的代码更易于理解和管理,而不是直接处理 WC API 时所需的更复杂的样式。它还具有这个简洁的模板系统,结合了 HTML 和 JS 模板字符串,使处理动态内容更加方便。这不仅有助于我们的编辑器中出现某些漂亮的颜色,还有助于其更新策略,即只更新 DOM 中已更改的部分。与手动更新相比,这可以提高性能。

综合考虑所有这些因素,如果您认真对待 WC,我想说值得一看,因为这个库的大小只有 6kb 左右。

本期话题是 —— 您开始使用 Web Components 了吗,有遭遇什么痛点吗?

欢迎在本文下方群聊自由言论,文明共享。谢谢大家的点赞,掰掰~

《前端 9 点半》每日更新,坚持阅读,自律打卡,每天一次,进步一点

Web Components,启动!

原文链接:https://juejin.cn/post/7334623638115647499 作者:人猫神话

(0)
上一篇 2024年2月15日 上午10:41
下一篇 2024年2月15日 上午10:51

相关推荐

发表回复

登录后才能评论