从零开始写一个微前端框架-样式隔离篇

本文是关于如何从零开始实现微前端框架的样式隔离功能的教程,属于系列文章的第三篇。通过改造子应用的CSS,添加唯一标识前缀避免样式冲突。详细介绍了样式隔离的实现原理、代码实现过程及验证方法,帮助读者理解微前端框架的样式管理。
摘要由CSDN通过智能技术生成

前言

自从微前端框架micro-app开源后,很多小伙伴都非常感兴趣,问我是如何实现的,但这并不是几句话可以说明白的。为了讲清楚其中的原理,我会从零开始实现一个简易的微前端框架,它的核心功能包括:渲染、JS沙箱、样式隔离、数据通信。由于内容太多,会根据功能分成四篇文章进行讲解,这是系列文章的第三篇:样式隔离篇。

通过这些文章,你可以了解微前端框架的具体原理和实现方式,这在你以后使用微前端或者自己写一套微前端框架时会有很大的帮助。如果这篇文章对你有帮助,欢迎点赞留言。

相关推荐

开始

前两篇文章中,我们已经完成了微前端的渲染和JS沙箱功能,接下来实现微前端的样式隔离。

问题示例

我们先创建一个问题,验证样式冲突的存在。在基座应用和子应用上分别使用div元素插入一段文字,两个div元素使用相同的class名text-color,分别在class中设置文字颜色,基座应用为red,子应用为blue

由于子应用是后来执行的,它的样式覆盖了基座应用,产生了样式冲突。

样式隔离实现原理

要实现样式隔离必须对应用的css进行改造,因为基座应用无法控制,我们只能对子应用进行修改。

先看一下子应用被渲染后的元素构造:

子应用的所有元素都被插入到micro-app标签中,且micro-app标签具有唯一的name值,所以通过添加属性选择器前缀micro-app[name=xxx]可以让css样式在指定的micro-app内生效。

例如:
.test { height: 100px; }

添加前缀后变为:
micro-app[name=xxx] .test { height: 100px; }

这样.test的样式只会影响到name为xxx的micro-app的元素。

渲染篇中我们将link标签引入的远程css文件转换为style标签,所以子应用只会存在style标签,实现样式隔离的方式就是在style标签的每一个CSS规则前面加上micro-app[name=xxx]的前缀,让所有CSS规则都只能影响到指定元素内部。

通过style.textContent获取样式内容是最简单的,但textContent拿到的是所有css内容的字符串,这样无法针对单独规则进行处理,所以我们要通过另外一种方式:CSSRules

当style元素被插入到文档中时,浏览器会自动为style元素创建CSSStyleSheet样式表,一个 CSS 样式表包含了一组表示规则的 CSSRule 对象。每条 CSS 规则可以通过与之相关联的对象进行操作,这些规则被包含在 CSSRuleList 内,可以通过样式表的 cssRules 属性获取。

形式如图:

所以cssRules就是由单个CSS规则组成的列表,我们只需要遍历规则列表,并在每个规则的选择器前加上前缀micro-app[name=xxx],就可以将当前style样式的影响限制在micro-app元素内部。

代码实现

创建一个scopedcss.js文件,样式隔离的核心代码都将放在这里。

我们上面提到过,style元素插入到文档后会创建css样式表,但有些style元素(比如动态创建的style)在执行样式隔离时还没插入到文档中,此时样式表还没生成。所以我们需要创建一个模版style元素,它用于处理这种特殊情况,模版style只作为格式化工具,不会对页面产生影响。

还有一种情况需要特殊处理:style元素被插入到文档中后再添加样式内容。这种情况常见于开发环境,通过style-loader插件创建的style元素。对于这种情况可以通过MutationObserver监听style元素的变化,当style插入新的样式时再进行隔离处理。

具体实现如下:

// /src/scopedcss.js

let templateStyle // 模版sytle

/**
 * 进行样式隔离
 * @param {HTMLStyleElement} styleElement style元素
 * @param {string} appName 应用名称
 */
export default function scopedCSS (styleElement, appName) {
   
  // 前缀
  const prefix = `micro-app[name=${
     appName}]`

  // 初始化时创建模版标签
  if (!templateStyle) {
   
    templateStyle = document.createElement('style')
    document.body.appendChild(templateStyle)
    // 设置样式表无效,防止对应用造成影响
    templateStyle.sheet.disabled = true
  }

  if (styleElement.textContent
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值