• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

120.乾坤css隔离机制

武飞扬头像
梅花十三儿
帮助1

  • 确保单实例场景子应用之间的样式隔离,但是无法确保主应用跟子应用、或者多实例场景的子应用样式隔离
start({sandbox : true})//沙箱隔离, 

判断沙箱隔离的方法,发现直接设置sandbox=true是不行的,需要使用experimentalStyleIsolation这个属性配置。

export function isEnableScopedCSS(sandbox: FrameworkConfiguration['sandbox']) {if (typeof sandbox !== 'object') {return false;}if (sandbox.strictStyleIsolation) {return false;}return !!sandbox.experimentalStyleIsolation;
} 
  • { strictStyleIsolation: true } 开启严格的样式隔离模式 ,shawod dom’
start({shadow:{ strictStyleIsolation: true }}) 

直观的可以看到,子应用的代码不是正常的dom,上面显示的shadow-root,先不管shadow-root是什么,接着往下看

学新通

  • experimentalStyleIsolation 给子应用加上自定义的data-xxx属性,相当于vue中我们通常使用的scoped,从生成的代码中可以看出来

学新通

在主应用中,通过配置sandbox做到样式隔离

start({ sandbox: { strictStyleIsolation: true } }); 

在start得时候配置得参数,但是只有等到start函数里面 frameworkStartedDefer.resolve() 之后才能往下执行. registerMicroApps只是准备好注册的应用配置信息,只有等调用了start方法之后,才会走registerApplication相关逻辑,registerApplicationsingle-spa中的一个主要的方法,乾坤实现微应用也主要用的是single-spa这个库

start 方法

export function start(opts: FrameworkConfiguration = {}) {frameworkConfiguration = { prefetch: true, singular: true, sandbox: true, ...opts };startSingleSpa({ urlRerouteOnly });started = true;//执行loadApp相关逻辑frameworkStartedDefer.resolve();
} 

修改appid得代码是在single-spa中还是qiankun中得?->qiankun,在处理模板的时候使用shadow dom实现的

loadApp中使用严格样式隔离的代码

export async function loadApp<T extends ObjectType>(app: LoadableApp<T>,configuration: FrameworkConfiguration = {},lifeCycles?: FrameworkLifeCycles<T>,
): Promise<ParcelConfigObjectGetter> {const strictStyleIsolation = typeof sandbox === 'object' && !!sandbox.strictStyleIsolation;let initialAppWrapperElement: HTMLElement | null = createElement(appContent,strictStyleIsolation,scopedCSS,appInstanceId,);
} 

createElement方法相关代码,我们在start方法中配置了strictStyleIsolation严格样式模式,因此会走到strictStyleIsolation判断相关逻辑里面,从这里面就可以看到创建shadow dom相关代码

function createElement(appContent: string,strictStyleIsolation: boolean,scopedCSS: boolean,appInstanceId: string,
): HTMLElement {const containerElement = document.createElement('div');containerElement.innerHTML = appContent;// appContent always wrapped with a singular divconst appElement = containerElement.firstChild as HTMLElement; //绝对样式隔离相关代码if (strictStyleIsolation) {//使用shadow做样式隔离const { innerHTML } = appElement;appElement.innerHTML = '';let shadow: ShadowRoot;if (appElement.attachShadow) {shadow = appElement.attachShadow({ mode: 'open' });} else {// createShadowRoot was proposed in initial spec, which has then been deprecatedshadow = (appElement as any).createShadowRoot();}shadow.innerHTML = innerHTML;}

 //...scopedCSS判断相关代码return appElement;
} 

使用scopedCss做到样式隔离

前面入口出的逻辑和shadow大致相同,scopedCss代码也很好理解,就是先查找要添加的应用是否有相应的属性,没有的话给子应用容器添加一个属性。然后遍历每个style标签,在每个style标签代码前面增加属性选择符,通过属性选择符 样式来确保样式不被重写

 if (scopedCSS) {const attr = appElement.getAttribute(css.QiankunCSSRewriteAttr);if (!attr) {//这边attr生成的属性:data-qiankun :vue2AppappElement.setAttribute(css.QiankunCSSRewriteAttr, appInstanceId);}const styleNodes = appElement.querySelectorAll('style') || [];forEach(styleNodes, (stylesheetElement: HTMLStyleElement) => {css.process(appElement!, stylesheetElement, appInstanceId);});} 

css.process方法

export const process = (appWrapper: HTMLElement,stylesheetElement: HTMLStyleElement | HTMLLinkElement,appName: string,
): void => {// lazy singleton patternif (!processor) {processor = new ScopedCSS();}const mountDOM = appWrapper;if (!mountDOM) {return;}const tag = (mountDOM.tagName || '').toLowerCase();if (tag && stylesheetElement.tagName === 'STYLE') {//生成前缀const prefix = `${tag}[${QiankunCSSRewriteAttr}="${appName}"]`;processor.process(stylesheetElement, prefix);}
}; 

什么是shadow dom?

可以将标记结构,样式和行为隐藏起来,和页面上其他代码相隔离。

shadow dom的一个demo:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><style> h1 {color: red;} </style><body><h1>hello 这个主页中的内容</h1><div id="box"></div></body><script> window.onload = function () {let box = document.getElementById("box");//开启shadow dombox.attachShadow({ mode: "open" });let shadow = box.shadowRoot;var h1 = document.createElement("h1");h1.innerHTML = "world 这是shaow dom中的内容";var style = document.createElement("style");style.textContent = `h1{color:green}`;shadow.appendChild(style);shadow.appendChild(h1);}; </script>
</html> 

学新通

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
学新通
学新通
学新通
学新通

有需要的小伙伴,可以点击下方卡片领取,无偿分享

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgcjejb
系列文章
更多 icon
同类精品
更多 icon
继续加载