最快最简单的方法就是直接上iframe,天然实现的 CSS 隔离。但是由于隔离的太好了,导致iframe内的弹窗蒙层无法全屏,用户体验不好。于是就有其他实现CSS 隔离的方案。

CSS隔离方案

  1. iframe隔离

  2. scoped隔离,都是玩过VUE的,在style标签增加scoped后,就可以使得当前CSS只作用于当前组件(生成一段唯一编码),参考实现方式应该也可以在微前端实现。

  3. 自己在选择器上下功夫,比如子A子应用就在所有的选择器前增加 .componentsA,子应用都使用预处理器的话也好操作。

  4. 拿到激活的子应用样式后,删除失活的子应用样式(不适合一个页面有2个以上的子应用的场景,而且会影响父元素)。

  5. Shadow DOM隔离,主流实现方式,下面细讲。

Shadow DOM

对于还不知道Shadow DOM是啥的哥们,你打开浏览器->开发者工具->设置(开发者工具的)->看下图

然后,恭喜你,哥们,你可以看到Shadow DOM了。你现在可以在Shadow DOM内看到很多原生DOM内部标签实现。

input-ShadowDOM

video-ShadowDOM

内部的样式与外面的样式是隔离的,这就是ShadowDOM,它不仅仅可以做到 DOM 元素的 CSS 样式隔离,还可以做到事件的隔离处理

示例

<body>
  <template id="shadowTemplate">
    <h1>Shadow DOM TEXT</h1>
    <button onclick="ShadowButton('ShadowDOM button')">
      Shadow DOM Button
    </button>
    <input onchange="ShadowInput(event)" value="Shadow DOM input" type="text">
  </template>

  <div id="shadow-outer">
    <button onclick="notShadowClick(event)">我不是 Shadow DOM 中的</button>
    <custom-element onclick="shadowTemplateClick(event)"></custom-element>
  </div>

  <script>

    function ShadowButton(e) {
      console.log("Shadow事件: ", e);
    }
    function ShadowInput(e) {
      console.log("ShadowInput的值: ", e.target.value);
    }
    function shadowTemplateClick(e) {
      console.log("shadowClick事件监听: ", e.target);
    }
    function notShadowClick(e) {
      console.log("普通事件: ", e.target);
    }

    class CustomElement extends HTMLElement {
      constructor() {
        super();
        // ShadowDOM的根节点
        const shadowRoot = this.attachShadow({ mode: "open" });
        // 获取挂载节点
        const $template = document.getElementById("shadowTemplate");
        // 挂载到根节点
        shadowRoot.appendChild($template.content.cloneNode(true));
      }
    }
    // 注册自定义元素
    customElements.define("custom-element", CustomElement);
  </script>
</body>

效果:

问题

ShadowDOM内部事件无法查看到内部触发事件的目标对象 Button 按钮,事件倒是正常,但是由于拿不到事件对象,那react开发者可就头疼了。都知道react(16,17以上该问题已不存在)一直是进行事件委托来处理事件,那么就会因为拿不到事件对象,而导致事件失效。

17+使用 React 挂载的 Root 节点进行事件委托,此时如果在 Shadow DOM 中使用 React 框架,那么事件可以被正确处理。具体原理请点击 -> click

未曾清贫难成人,不经打击老天真。 自古英雄出炼狱,从来富贵入凡尘。 醉生梦死谁成气,拓马长枪定乾坤。 挥军千里山河在,立名扬威传后人。