likes
comments
collection
share

Web Components的前世今生

作者站长头像
站长
· 阅读数 10

引言

发展历史

Web Components 技术的发展历程可以分为以下几个阶段:

  1. 2011 年,Google 开始开发 Polymer 项目,旨在创建一种基于 Web 标准的新型 Web 应用开发框架。
  2. 2013 年,W3C 开始制定 Web Components 标准,包括 Custom Elements、HTML Templates 和 Shadow DOM 等技术。
  3. 2015 年,Web Components 1.0 草案发布。
  4. 2017 年,Web Components 1.0 正式标准发布。
  5. 2018 年,Chrome 63 正式支持 Web Components 技术。
  6. 2019 年,Web Components 技术开始逐渐被更多的前端开发人员使用,成为前端开发的基础设施之一

谁在使用

1. youtube

Web Components的前世今生

2. github

Web Components的前世今生

3.quark-design(哈啰)

Web Components的前世今生

4.Vue也支持web Components

Web Components的前世今生

目标

了解web Components是什么。本文不是全面教程,只是一个简单演示,如果需要全面学习的话可以点我 进行全面学习

Web Components的基本概念

Web Component 是一套不同的技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 web 应用中使用它们。

如图, Web Components主要包括了下面的三个技术

Web Components的前世今生

Custom Elements

概念

由 Web 开发人员定义行为的 HTML 元素,扩展了浏览器中可用的元素集

实现方式有两种

例子

如果你有vue的基础的话,vue的语法中有一个动态组件有一个attribute is,代表的是哪个组件,这个自定义内置元素和vue的语法很像 Web Components的前世今生

可以先看下方的自定义元素的例子,我们对下面的代码做个解释

  1. html中 p 标签的is 后有一个word-count 代表的就是我们使用了word-count的自定义元素
  2. script脚本中定义了一个wordCount类继承自HTMLParagraphElement
  3. 在这个类中定义了一单词统计的功能
  4. 最后注册了自定义元素(通过customElements)
<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
 </head>
 <body>
   <div>
       <article contenteditable="">
           <p>my name is  a du</p>
           <p is="word-count"></p>
       </article>
   </div>
   <script>
     class WordCount extends HTMLParagraphElement {
       constructor() {
         super();
         // 得到父亲节点
         var wcParent = this.parentNode;
         // 创建影子节点
         var shadow = this.attachShadow({ mode: "open" });
         var count = "Words: " + countWords(wcParent);
         // 创建一个span节点
         var text = document.createElement("span");
         text.textContent = count;
         // 将创建的节点添加到影子节点
         shadow.appendChild(text);
         //200ms 更新字数统计
         setInterval(function () {
           var count = "Words: " + countWords(wcParent);
           text.textContent = count;
         }, 200);
         //定义统计字数的方法
         function countWords(node) {
           var text = node.innerText || node.textContent;
           return text.split(/\s+/g).length;
         }
       }
     }
     customElements.define("word-count", WordCount, { extends: "p" });
   </script>
 </body>
</html>

上方的代码的预览效果

Web Components的前世今生

生命周期

当然自定义元素也有有生命周期的,我们对上方的代码进行扩展 Web Components的前世今生

改动点为

  1. 添加了个删除的button
  2. 在constuctor下方的节点添加了两个事件connectedCallback(当自定义元素第一次被连接到文档 DOM 时被调用。)、disconnectedCallback(当自定义元素与文档 DOM 断开连接时被调用)

下方为demo的预览gif Web Components的前世今生

当然Custom element 还有更多的生命周期(adoptedCallback、attributeChangedCallback),我们就不介绍了。

Shadow DOM

概念

对标签和样式的一层 DOM 包装,你将一个 DOM 树附加到一个元素上,并且使该树的内部对于在页面中运行的 JavaScript 和 CSS 是隐藏的。

设置浏览器

这个概念也许有点模糊,我们先不写代码,先打开你的浏览器设置,我们来看个设置

shadow Dom 也许你不注意,平常使用的input,video等其实都是由shadow dom开发的

首先打开浏览器控制台的设置选项

Web Components的前世今生 然后再找到Preference -> Elements,把show user anent shadow dom勾上 Web Components的前世今生

)

浏览器的video,为什么我们只是引入了,就自动生成了暂停、音量、进度条,其实这些都是shadow Dom的的功劳 Web Components的前世今生

例子

关键代码解释

  1. attachShadow() 来创建影子 DOM
  2. mode 设置为 "open" 时,页面中的 JavaScript 可以通过影子宿主的 shadowRoot 属性访问影子 DOM 的内部。

很简单的代码,我们就创建了一个shadow dom

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="host"></div>
    <span>我是普通dom</span>
    <script>
      const host = document.querySelector("#host");
      const shadow = host.attachShadow({ mode: "open" });
      const span = document.createElement("span");
      span.textContent = "我是shadow dom";
      shadow.appendChild(span);
    </script>
  </body>
</html>

运行效果如下 Web Components的前世今生

对JS上来说基本上是隐藏的

通过querySelector是获取不到元素的,{ mode: "open" } 传入 attachShadow()。当 mode 设置为 "open" 时,页面中的 JavaScript 可以通过影子宿主的 shadowRoot 属性访问影子 DOM 的内部,当mode是closed,此时 shadowRoot 返回 null

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="host"></div>
    <span>我是普通dom</span>
    <button onClick="onLogSpanLength()">打印Span的长度</button>
    <script>
      const host = document.querySelector("#host");
      const shadow = host.attachShadow({ mode: "open" });
      const span = document.createElement("span");
      span.textContent = "我是shadow dom";
      shadow.appendChild(span);
      function onLogSpanLength() {
        console.log(document.querySelectorAll("span").length);
        console.log(document.querySelector("#host").shadowRoot.querySelectorAll("span").length)
      }
    </script>
  </body>
</html>
 

运行效果如下

Web Components的前世今生

CSS封闭性

保持上方的代码不变,我们添加一个css的样式,

    <style>
      span {
        color: blue;
        border: 1px solid black;
      }
    </style>

运行效果

Web Components的前世今生

shadow dom 的特点

从前面的介绍,我们知道shadow dom是游离在 DOM 树之外的节点树,但是它是基于普通 DOM 元素(非 document)创建的,并且创建后的 Shadow-dom 节点可以从界面上直观的看到。最重要的一点是Shadow-dom 具有良好的密封性。

Template和Slot

template概念

template 顾名思义是模板,他有以下的特点 HTML 内容模板<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可以在运行时使用 JavaScript 实例化。

Web Components的前世今生

上面的代码不会展示在你的页面中,直到你用 JavaScript 获取它的引用,然后添加到 DOM 中,如下面的代码:

Web Components的前世今生

slot

熟悉 Vue 的同学应该都知道”插槽(slot)“的概念,通过使用插槽可以让页面内容的组织更加灵活。

的确,vue的设计灵感也来源此,下方的为官方的一个截图

Web Components的前世今生

例子

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 定义一个模板 -->
    <template id="templateId">
      <slot name="element-name">插槽的默认值</slot>
    </template>
    <element-test> </element-test>
    <element-test>
      <span slot="element-name">测试值</span>
    </element-test>
    <script>
      customElements.define(
        "element-test",
        class extends HTMLElement {
          constructor() {
            super();
            // 获取模板的内容
            const template = document.getElementById(
              "templateId"
            ).content;
            // 创建一个shadow节点
            const shadowRoot = this.attachShadow({ mode: "open" }).appendChild(
              //将模板的拷贝到阴影的根结点上
              template.cloneNode(true)
            );
          }
        }
      );
    </script>
  </body>
</html>


效果如下图

Web Components的前世今生

调试

使用方式基本同vuedevtool相同 下载地址 下方的为github的截图

Inspector的Tab

我们可以看到Proprrties、attriubutes、methods Web Components的前世今生

Source的Tab

Web Components的前世今生

在实际开发中的应用

图片添加header

当公司要求所有的请求包含图片添加 token图片添加自定义的header

方便调试样式

假如设计师设计了placeholder为不同颜色,当我们不开启浏览器的默认样式的时候,看不到placeholder的内容,开启后,可以方便的看到内容,并且进行修改。

下方的截图为element ui的input的placeholder样式

Web Components的前世今生

更好的理解不同的框架的配置

比如我们公司使用的是qiankun

下方的为qiankun的截图,当你理解了shadowDom,你就可以更快的知道这个配置项的作用

Web Components的前世今生

转载自:https://juejin.cn/post/7308782855941242906
评论
请登录