广告位联系
返回顶部
分享到

微前端之js隔离样式隔离 元素隔离问题介绍

JavaScript 来源:互联网 作者:佚名 发布时间:2022-08-24 10:54:35 人浏览
摘要

WebComponent 介绍 微前端框架中,js隔离、样式隔离、元素隔离是必须解决的三个问题,下面我们就来分别说说这三个问题是什么?怎么解决? 涉及的核心点是 Proxy,WebComponent,shadowDOM

WebComponent 介绍

微前端框架中,js隔离、样式隔离、元素隔离是必须解决的三个问题,下面我们就来分别说说这三个问题是什么?怎么解决?

涉及的核心点是 Proxy,WebComponent,shadowDOM

WebComponent 不在这三个问题中,但是我们做个简单介绍

浏览器默认的标签有 div,a,p等等,浏览器是会自动识别,并且有默认的事件和样式。

浏览器相对于提供了WebComponent,我们可以自定义Html标签,注意规定自定义标签需要包含横线,如<user-card>,父类都是HTMLElement

attachShadow 是大多数标签都支持的,比如 div,p,selection,但是a,ul,li等不支持,如果执行attachShadow,那么组件的html结构会挂在shadowRoot下,否则直接挂着组件下。

用法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

class UserCard extends HTMLElement {

  static get observedAttributes() {return ['name', 'url']; }

  constructor() {

    super();

    // 可以创Shadom,通过this.shadowRoot获取

    // this.attachShadow({ mode: 'open' })

  }

  connectedCallback (){

      console.log('钩子,元素append到ducument触发')

  }

  disconnectedCallback (){

      console.log('钩子,元素从document删除触发')

  }

  // 只有observedAttributes 中监听的属性name,url变化会触发下面回调

  attributeChangedCallback (attr, oldVal, newVal){

      console.log('钩子,元素属性改变时触发')

  }

}

window.customElements.define('user-card', UserCard);

更新细节查看 web自定义元素

js隔离

问题

主要是很对全局变量window

  • 情况1:都对全局变量赋值

应用A,写 window.r = 1;

然后有应用B,又写 window.r = 2,这就乱套了

  • 情况2:都设置事件

应用A,window.addEventListener('click',()=>console.log('A'));

应用B,window.addEventListener('click',()=>console.log('B'));

这就乱套了

解决

对应全局对象,各个应该要独立,怎么实现呢,有两种方法

方法一用 Proxy 代理

es2015 Reflect属于一个静态类或者设置属性等用法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

const rawWindow = window

const proxyWindow = new Proxy({},{

    get: (target, key): unknown => {

        // 原 target 上有就返回,否则返回 rawWindow 属性

        return Reflect.has(target, key) ? Reflect.get(target, key) : Reflect.get(rawWindow, key)

    },

    set: (target, key, value): boolean => {

        if(!Object.prototype.hasOwnProperty.call(target, key) && Object.prototype.hasOwnProperty.call(rawWindow, key)){

            const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key)

            const { configurable, enumerable, writable, set } = descriptor!

            // set value because it can be set

            rawDefineProperty(target, key, {

              value,

              configurable,

              enumerable,

              writable: writable ?? !!set,

            })

        } else {

            Reflect.set(target, key, value)

        }

    }

})

将 window.r = 1 和 window.addEventListener('click',()=>console.log('A')) 包括到自执行函数里面

A和B互不干扰

1

2

3

4

;(function(window){

    window.r = 1

    window.addEventListener('click',()=>console.log('A'))

})(proxyWindowA)

1

2

3

4

;(function(window){

    window.r = 2

    window.addEventListener('click',()=>console.log('B'))

})(proxyWindowB)

方法二 用快照

快照隔离有个前提条件是,当前还有一个应用显示,不能出现多个应用并存显示在界面上,应用A,B切换时,比如当前应用是A,现在要切入到应用B

  • 暂存起来应用A的全局变量和事件
  • 恢复全局变量和事件到应用A之前
  • 检查之前是否保持有应用B的全局变量和事件,如果有,则载入

样式隔离

问题

同理,各个应用之前可能相互设置标签样式,会相互影响,或者影响全局样式,比如应用A给body设置样式,应用B也给body设置样式

方法一 样式增加不同前缀

每个应用通过前缀独立区分开,京东micro-app默认是采用的这个策略,唯一注意的一个小点是,基座样式会影响子应用的样式,所以需要注意基座中不要写太多样式

方法二 ShadawDom

大多数Html标签都有 attachShadow() 方法给指定的元素挂载一个 Shadow DOM。参数是open或closed

ShadawDom 样式绝对隔离,不用加前缀,如下图

用法

1

2

//open 是外界可以访问到Element.shadowRoot再访问到内部元素,closed就是完全不能访问内部元素

var shadowroot = element.attachShadow('open|closed') 

元素隔离

元素隔离是 基座应用和子应用都有一个元素<div id='root'></div>,此时子应用通过document.querySelector('#root'),因为js隔离已经做了代理,此时document.querySelector只是子应用本身了


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/7134178779349385247
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计