Web Component小记

前言

前端组件化可以并不基于JS框架完成吗?本质上,JS完全可以做到,真正阻碍前端组件化的是另外两个小朋友,CSS和DOM。

web component

WebComponent给出的解决思路是提供了对局部视图封装能⼒,可以让DOM、CSSOM和JavaScript运行在局部环境中,这样就使得局部的CSS和DOM不会影响到全局。这是一套技术的组合,包括自定义元素,shadow DOM和HTML模板,我们拿一段代码分析一下:


<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Documenttitle>
  head>
  <body>
    <template id="headers">
      <style>
        div {
          background: #3e3;
          width: 300px;
          height: 300px;
          box-shadow: antiquewhite 10px 10px;
          color: red;
          margin: 0 auto;
          font-size: 56px;
        }
      style>
      <script>
        function foo() {
          console.log("green foo");
        }
      script>
      <div>
        this is a green div
      div>
    template>
    <script>
      class ShadowDOM extends HTMLElement {
        constructor() {
          super();
          const content = document.querySelector("#headers").content;
          const shadow = this.attachShadow({ mode: "open" });
          shadow.appendChild(content.cloneNode(true));
        }
      }
      customElements.define("header-component", ShadowDOM);
    script>
    <header-component>header-component>
    <div>this is a web componentdiv>
  body>
html>

分析一下,这段代码其实总共做了三件事,分别是构建shadow,挂载shadow,展示shadow。

首先是构建:

    <template id="headers">
      <style>
        div {
          background: #3e3;
          width: 300px;
          height: 300px;
          box-shadow: antiquewhite 10px 10px;
          color: red;
          margin: 0 auto;
          font-size: 56px;
        }
      style>
      <script>
        function foo() {
          console.log("green foo");
        }
      script>
      <div>
        this is a green div
      div>
    template>

使用template进行包裹,和其他标签一样,里面style,script或者html标签都可以写,这一段比较好理解。

第二段:

    <script>
      class ShadowDOM extends HTMLElement {
        constructor() {
          super();
          const content = document.querySelector("#headers").content;
          const shadow = this.attachShadow({ mode: "open" });
          shadow.appendChild(content.cloneNode(true));
        }
      }
      customElements.define("header-component", ShadowDOM);
    </script>

即挂载,这里定义了一个shaowDOM 类去继承HTMLELement,然后拿到template里面的content,然后使用attachShadow方法辅助构建shadow,接着只需要把content加到shadow上面即可。

最后只需要定义这个component即可,customElements.define的第一个参数即 component的名字,第二个即shadowDOM。

第三段,就和Vue、React一样直接使用即可。

但是需要注意的是,shadowDOM可以隔绝DOM和CSS,却无法隔绝JS,我们在网页直接调foo函数,可以正常调用。这部分原因大概是JS的组件化已经做的够好了,不需要画蛇添足了。

原理简要分析

当⽣成布局树的时候,渲染引擎会判断headers属性下的shadow-root元素是否是shadowDOM, 如果是,那么在shadowDOM内部元素的节点选择CSS样式的时候,会直接使⽤shadowDOM内部的CSS属性,这样最终渲染出来的效果就是影⼦DOM内部定义的样式。

你可能感兴趣的:(H5C3)