微前端之?js隔離?樣式隔離?元素隔離問題詳解
WebComponent 介紹
微前端框架中,js隔離、樣式隔離、元素隔離是必須解決的三個(gè)問題,下面我們就來分別說說這三個(gè)問題是什么?怎么解決?
涉及的核心點(diǎn)是 Proxy,WebComponent,shadowDOM
WebComponent 不在這三個(gè)問題中,但是我們做個(gè)簡(jiǎn)單介紹
瀏覽器默認(rèn)的標(biāo)簽有 div,a,p等等,瀏覽器是會(huì)自動(dòng)識(shí)別,并且有默認(rèn)的事件和樣式。
瀏覽器相對(duì)于提供了WebComponent,我們可以自定義Html標(biāo)簽,注意規(guī)定自定義標(biāo)簽需要包含橫線,如<user-card>,父類都是HTMLElement
attachShadow 是大多數(shù)標(biāo)簽都支持的,比如 div,p,selection,但是a,ul,li等不支持,如果執(zhí)行attachShadow,那么組件的html結(jié)構(gòu)會(huì)掛在shadowRoot下,否則直接掛著組件下。
用法
class UserCard extends HTMLElement {
static get observedAttributes() {return ['name', 'url']; }
constructor() {
super();
// 可以創(chuàng)Shadom,通過this.shadowRoot獲取
// this.attachShadow({ mode: 'open' })
}
connectedCallback (){
console.log('鉤子,元素append到ducument觸發(fā)')
}
disconnectedCallback (){
console.log('鉤子,元素從document刪除觸發(fā)')
}
// 只有observedAttributes 中監(jiān)聽的屬性name,url變化會(huì)觸發(fā)下面回調(diào)
attributeChangedCallback (attr, oldVal, newVal){
console.log('鉤子,元素屬性改變時(shí)觸發(fā)')
}
}
window.customElements.define('user-card', UserCard);
更新細(xì)節(jié)查看 web自定義元素
js隔離
問題
主要是很對(duì)全局變量window
- 情況1:都對(duì)全局變量賦值
應(yīng)用A,寫 window.r = 1;
然后有應(yīng)用B,又寫 window.r = 2,這就亂套了
- 情況2:都設(shè)置事件
應(yīng)用A,window.addEventListener('click',()=>console.log('A'));
應(yīng)用B,window.addEventListener('click',()=>console.log('B'));
這就亂套了
解決
對(duì)應(yīng)全局對(duì)象,各個(gè)應(yīng)該要獨(dú)立,怎么實(shí)現(xiàn)呢,有兩種方法
方法一用 Proxy 代理
es2015 Reflect屬于一個(gè)靜態(tài)類或者設(shè)置屬性等用法
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')) 包括到自執(zhí)行函數(shù)里面
A和B互不干擾
;(function(window){
window.r = 1
window.addEventListener('click',()=>console.log('A'))
})(proxyWindowA)
;(function(window){
window.r = 2
window.addEventListener('click',()=>console.log('B'))
})(proxyWindowB)
方法二 用快照
快照隔離有個(gè)前提條件是,當(dāng)前還有一個(gè)應(yīng)用顯示,不能出現(xiàn)多個(gè)應(yīng)用并存顯示在界面上,應(yīng)用A,B切換時(shí),比如當(dāng)前應(yīng)用是A,現(xiàn)在要切入到應(yīng)用B
- 暫存起來應(yīng)用A的全局變量和事件
- 恢復(fù)全局變量和事件到應(yīng)用A之前
- 檢查之前是否保持有應(yīng)用B的全局變量和事件,如果有,則載入
樣式隔離
問題
同理,各個(gè)應(yīng)用之前可能相互設(shè)置標(biāo)簽樣式,會(huì)相互影響,或者影響全局樣式,比如應(yīng)用A給body設(shè)置樣式,應(yīng)用B也給body設(shè)置樣式
方法一 樣式增加不同前綴
每個(gè)應(yīng)用通過前綴獨(dú)立區(qū)分開,京東micro-app默認(rèn)是采用的這個(gè)策略,唯一注意的一個(gè)小點(diǎn)是,基座樣式會(huì)影響子應(yīng)用的樣式,所以需要注意基座中不要寫太多樣式

方法二 ShadawDom
大多數(shù)Html標(biāo)簽都有 attachShadow() 方法給指定的元素掛載一個(gè) Shadow DOM。參數(shù)是open或closed
ShadawDom 樣式絕對(duì)隔離,不用加前綴,如下圖
用法
//open 是外界可以訪問到Element.shadowRoot再訪問到內(nèi)部元素,closed就是完全不能訪問內(nèi)部元素
var shadowroot = element.attachShadow('open|closed')

元素隔離
元素隔離是 基座應(yīng)用和子應(yīng)用都有一個(gè)元素<div id='root'></div>,此時(shí)子應(yīng)用通過document.querySelector('#root'),因?yàn)閖s隔離已經(jīng)做了代理,此時(shí)document.querySelector只是子應(yīng)用本身了
以上就是微前端之 js隔離 樣式隔離 元素隔離問題詳解的詳細(xì)內(nèi)容,更多關(guān)于微前端js 樣式 元素隔離的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript自動(dòng)化測(cè)試添加頁(yè)面DOM元素唯一ID方案示例
這篇文章主要為大家介紹了JavaScript自動(dòng)化測(cè)試添加頁(yè)面DOM元素唯一ID方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
document 和 document.all 分別什么時(shí)候用
document 和 document.all 分別什么時(shí)候用...2006-06-06
javascript 操作cookies詳解及實(shí)例
這篇文章主要介紹了javascript 操作cookies詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
微信小程序 ES6Promise.all批量上傳文件實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序 ES6Promise.all批量上傳文件實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04

