micro-app的css样式隔离

news2024/11/16 7:22:25

手写微前端micro-app-CSS隔离

子应用的CSS可能会对基座应用或者其他子应用产生的影响

首先现在我们把react页面放入到vue2的页面大家也能看到一些问题了,在react中的index.css中对body的一些css样式,已经影响了基座应用的css。

为了看的更明显,我自己写一下,在基座应用(vue2)中声明一个css样式,比如:

.text-color{
	color:red
}

做实验的时候,如果是vue2项目。别把这个样式写到了带scoped的style样式标签中了,这种本身就是隔离的,我们这里所谓的隔离,主要是针对全局样式

由于我们前面的处理只是将link标签转换为了style标签,因此在react项目中做处理的话,最好将样式写在静态css文件中,比如之前讲index.css文件放到了index.html中

如果在子应用中,也有同名的全局样式

.text-color{
	color:yellow
}

那么,你会发现,子应用的这个样式,对基座应用中,同样使用这个样式的标签起了作用,我们就是要隔绝这种情况

在这里插入图片描述

比如上面的.text-color这个样式,在子应用中,我们就可能会加上

micro-app[name=app] .text-color

2、代码实现

首先创建新的文件scopedcss.js,创建scopedCSS函数,来进行css过滤替换处理。从上面的演示可以分析出,这个函数我们至少需要两个参数

1、style节点对象,通过这个对象获取textContent与sheet的值

2、子应用app的名字,因为我们需要这个名字来组装前缀

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

你会发现打印了textContent的内容,但是sheet内容却为空,原因是css没有挂载到页面之前,样式表还没生成。是获取不了sheet的。而且有时候style元素(比如动态创建的style)在执行样式隔离时还没插入到文档中,此时样式表还没生成。也会出现这种情况

不能获取sheet内容的话,我们仅仅凭借textContent字符串的内容,去做处理工作量太大,也不好区分css中的内容

所以我们做一个取巧的办法,声明一个临时的style模板,用来填充css,用完之后删除

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

  // console.log(styleElement.sheet);
  // console.log(styleElement.textContent);

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

  if (styleElement.textContent) {
    // 将元素的内容赋值给模版元素
    templateStyle.textContent = styleElement.textContent
    // 获取临时模板中的sheet
    console.log(templateStyle.sheet)
  } 
}

我们需要的是将**@media内部的.text加上前缀,而这些,sheet中的cssRules**已经帮我们划分了类型了,类型有数十种,我们只处理STYLE_RULEMEDIA_RULESUPPORTS_RULE三种类型

  • type为1的,是普通的样式STYLE_RULE

  • type为4的,是media类型,MEDIA_RULE

  • type为12的,为supports类型SUPPORTS_RULE

也就是说,我们需要根据类型不一样,分开进行处理。其实分开处理无非也就是mediasupports类型,再递归执行一下

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) {
    // 将元素的内容赋值给模版元素
    templateStyle.textContent = styleElement.textContent
    // console.log(templateStyle.sheet)
    // 格式化规则,并将格式化后的规则赋值给style元素
    styleElement.textContent = scopedRule(Array.from(templateStyle.sheet.cssRules || []), prefix)
    // 清空模版style内容
    templateStyle.textContent = ''
  } 
}

/**
 * 依次处理每个cssRule
 * @param rules cssRule
 * @param prefix 前缀
 */
function scopedRule (rules, prefix) {
  let result = ''
  // 遍历rules,处理每一条规则
  for (const rule of rules) {
    switch (rule.type) {
      case 1: // STYLE_RULE
        result += scopedStyleRule(rule, prefix)
        break
      case 4: // MEDIA_RULE
        result += scopedPackRule(rule, prefix, 'media')
        break
      case 12: // SUPPORTS_RULE
        result += scopedPackRule(rule, prefix, 'supports')
        break
      default:
        result += rule.cssText
        break
    }
  }

  return result
}

// 处理media 和 supports
function scopedPackRule (rule, prefix, packName) {
  // 递归执行scopedRule,处理media 和 supports内部规则
  const result = scopedRule(Array.from(rule.cssRules), prefix)
  return `@${packName} ${rule.conditionText} {${result}}`
}

递归之后,最终其实还是使用**scopedStyleRule()**函数进行处理。这个函数难度最大,因为要写难度的很大的正则表达式,太复杂了,我也不会,找了一下micro-app的源码

/**
 * 修改CSS规则,添加前缀
 * @param {CSSRule} rule css规则
 * @param {string} prefix 前缀
 */
function scopedStyleRule (rule, prefix) {
  // 获取CSS规则对象的选择和内容
  const { selectorText, cssText } = rule

  // 处理顶层选择器,如 body,html 都转换为 micro-app[name=xxx]
  if (/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
    return cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix)
  } else if (selectorText === '*') {
    // 选择器 * 替换为 micro-app[name=xxx] *
    return cssText.replace('*', `${prefix} *`)
  }

  // 匹配顶层选择器,如 body,html
  const builtInRootSelectorRE = /(^|\s+)((html[\s>~]+body)|(html|body|:root))(?=[\s>~]+|$)/

  // 匹配查询选择器
  return cssText.replace(/^[\s\S]+{/, (selectors) => {
    return selectors.replace(/(^|,)([^,]+)/g, (all, $1, $2) => {
      // 如果含有顶层选择器,需要单独处理
      if (builtInRootSelectorRE.test($2)) {
        // body[name=xx]|body.xx|body#xx 等都不需要转换
        return all.replace(builtInRootSelectorRE, prefix)
      }
      // 在选择器前加上前缀
      return `${$1} ${prefix} ${$2.replace(/^\s*/, '')}`
    })
  })
}

效果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1612327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】git

大家好,我是苏貝,本篇博客带大家了解Linux的编译器-gcc/g,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1.安装git2.在gitee上创建仓库3.首次配置4.下载仓库到本地5.三板斧6.git log7.gi…

STL::string简单介绍

目录 1、什么是STL STL6大组件:仿函数、算法、容器、空间配置器、迭代器、配接器 推荐文档(必须学会看文档) 2、string常用接口 a、初始化 1、什么是STL 标准模板库 STL(Standard Template Library),主要是数据结构…

【C++程序员的自我修炼】初识模板

云收天彩色 木叶落秋声 目录 函数模板 函数模板的实现 函数模板的实例化 模板参数的匹配原则 参数模板推不出来的情况 类模板 类模板的定义格式 类模板的实例化 契子 ✨ 我们在学 C语言 的时候应该都写过交换两个数的函数 swap 吧 当时我们只是写了 int 类型,那…

sherpa + ncnn 离线语音识别

目录结构 前言音视频格式转为wavsherpa-ncnn编译LinuxWindowswindows编译中遇到的问题问题“nmake -? failed with: no such file or directory”编译失败原因 成功编译截图 可执行程序说明模型下载语言识别测试LinuxWindows 参考文献 前言 小编需要实现离线音视频语言部分识…

#STM32F407VET6(天空星)标准库和HAL驱动ILI9341

一、驱动方式:软件SPI,屏幕像素320*240 二、标准库含触摸,HAL库不含触摸 三、立创参考的文档 【立创天空星ST32F407VET6】模块移植手册 - 飞书云文档 (feishu.cn)https://lceda001.feishu.cn/wiki/MFNpw4STVi5ImikkcH1clWrlnqb 四、引脚分…

ElasticSearch中使用向量和关键词联合检索

注:案例测试数据及其索引构建详见:ElasticSearch中使用bge-large-zh-v1.5进行向量检索(一)-CSDN博客 中的第三部分。 假设任务场景为:用“新疆”向量检索相关的数据,同时需要匹配关键词“巴州”。 首先获取…

C#到底属于编译型语言还是解释型语言?

C#是一种编译型语言,也称为静态类型语言,这意味着C#代码在运行之前需要经过编译器的编译处理,并生成一个可执行的本地代码文件(通常是.exe或.dll文件)。相反,解释型语言将代码转换为低级代码后直接执行&…

【结构型模式】装饰器模式

​一、装饰器模式概述 装饰器模式(装饰者模式)定义:装饰器模式动态地将责任附加到对象上。若要拓展功能,装饰者提供了比继承更有弹性地替代方案。(对象结构型模型)通俗点来说:动态的给一个对象增…

12.事件参数

事件参数 事件参数可以获取event对象和通过事件传递数据 获取event对象 <template><button click"addCount">Add</button><p>Count is: {{ count }}</p> </template> <script> export default {data() {return {count:0…

13.Hexo Plugins插件及将网站上传到互联网

Plugins 有些想要实现的操作Hexo实现不了&#xff0c;这时就可以使用插件 插件一般都是可以下载的代码片段&#xff0c;可以附加到Hexo上 添加了一些功能或一些额外的东西 Plugins | Hexo 在官方页面&#xff0c;有471个插件&#xff0c;并附加了一些描述 点击一个插件时&…

【研发管理】产品经理知识体系-文化、团队与领导力

导读&#xff1a;文化、团队与领导力是产品经理知识体系中的重要组成部分。产品经理需要深入理解并应用这些要素&#xff0c;以推动产品的成功开发和运营。通过塑造积极的文化氛围、建立高效的团队和发挥领导力&#xff0c;产品经理能够为公司创造更大的价值。 目录 概述 1、…

(1)认识人工智能

第一章 认识人工智能 引言 本人目前大三&#xff0c;双非一本的人工智能专业&#xff0c;代码能力不算太差&#xff0c;做过项目&#xff0c;也打了比赛&#xff0c;获了奖&#xff0c;但是走技术路线总会有否定自己的感觉&#xff0c;可能是感觉自己的才能没有在搞技术方面实…

#QT获取ONENET云平台数据(草稿)

1.基本目标 &#xff08;1&#xff09;查询ONENT云平台的数据 &#xff08;2&#xff09;查询网络时间 &#xff08;3&#xff09;网络音乐拉取&#xff08;作为背景音乐&#xff09;&#xff0c;音量可调 2.制作UI界面 &#xff08;1&#xff09;串口图标的制作方法 &…

RIME-SVM,基于RIME寒冰优化算法优化SVM支持向量机回归预测 (多输入单输出)-附代码

支持向量机&#xff08;SVM&#xff09; 支持向量机&#xff08;SVM&#xff09;是一种广泛用于分类和回归的强大监督学习算法。在回归任务中&#xff0c;特别是在SVM被用作支持向量回归&#xff08;SVR&#xff09;时&#xff0c;目标是找到一个函数&#xff0c;这个函数在给…

PMP证书难考吗?

PMP证书难不难考要看你学的咋样的&#xff0c;我的PMP认证就是一个多月拿下的&#xff0c;同一个考次的同学在考试前的讲师直播过程中一直在说冲刺题难怎么怎么滴&#xff0c;最后还是通过率98%&#xff0c;绝大多数都通过了&#xff0c;并且还有47%的同学考了3A&#xff0c;这…

Vue2slot插槽(理解与应用)

1、插槽的概念 插槽&#xff08;Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时&#xff0c;把不确定的、希望由用户指定的部分定义为插槽。 举个例子&#xff1a;组件好比小霸王游戏机&#xff0c;插槽就是游戏机的插口&#xff0c;看用户插什么卡&#xff0c;就…

笔记 | 嵌入式系统概论

1 嵌入式系统简介 1.1 嵌入式系统的定义 根据美国电气与电子工程师学会&#xff08;IEEE&#xff1a;Institute of Electrical and Electronics Engineers )的定义&#xff0c;嵌入式系统是用于控制、监视或辅助操作机器和设备的装置(原文: devices used to control, monitor…

【Java基础】23.接口

文章目录 一、接口的概念1.接口介绍2.接口与类相似点3.接口与类的区别4.接口特性5.抽象类和接口的区别 二、接口的声明三、接口的实现四、接口的继承五、接口的多继承六、标记接口 一、接口的概念 1.接口介绍 接口&#xff08;英文&#xff1a;Interface&#xff09;&#xf…

Virtualenv:Python项目管理的救星

在Python的世界里&#xff0c;依赖包冲突是开发者的噩梦&#xff0c;但也是成长的催化剂。最近在写Python项目中就碰到了这样的问题&#xff0c;明明代码在自己的电脑上表现都是正常的&#xff0c;在另外一台电脑上却始终有些小问题&#xff0c;两台电脑安装的Python版本都是一…

云原生Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境

前言 构建可移植的计算机视觉环境 文章目录 前言引言简介&#xff1a;目的和重要性&#xff1a; 深入理解Docker和OpenCVDocker的基本概念和优势&#xff1a;OpenCV简介和应用领域&#xff1a; 构建Docker镜像部署分享Docker容器1. 打包Docker镜像:2. 上传到Docker镜像仓库:3. …