前言
突然对shadowdom感兴趣了,然后实现发现了很多坑,特此总结一下。
实现原理
函数组件我实现的有点bug,就是子组件的自己的状态无法改变,暂时不清楚为啥,如果有需要可以看一下react-shadow的实现:https://github.com/Wildhoney/ReactShadow/blob/master/src/core/index.js#L19 类组件实现起来倒是没啥问题:
export class ShadowView extends React . Component {
state: {
root: null | ShadowRoot;
pdiv: null | HTMLDivElement;
div: null | HTMLDivElement;
} = {
root: null ,
pdiv: null ,
div: null ,
} ;
setRoot = ( pdiv: HTMLDivElement) => {
if ( pdiv) {
const div = document. createElement ( "div" ) ;
const shadow = div. attachShadow ( { mode: "open" } ) ;
pdiv. appendChild ( div) ;
this . setState ( { root: shadow, pdiv, div } ) ;
}
} ;
componentWillUnmount ( ) {
if ( this . state. pdiv && this . state. div) {
this . state. pdiv! . removeChild ( this . state. div) ;
this . setState ( ( pre) => ( { ... pre, root: null , div: null } ) ) ;
}
}
render ( ) {
const { children } = this . props;
const { root } = this . state;
return (
< div ref= { this . setRoot} >
{ root &&
ReactDOM. createPortal ( children, root as unknown as Element) }
< / div>
) ;
}
}
export function Axxx ( props: { state: string ; cl: Function } ) {
const [ state, setState] = useState ( 0 ) ;
return (
< div className= "aaa" >
xcsdsasdasdasdsad
{ props. state}
{ state}
< button
onClick= { ( ) => {
setState ( ( pre) => pre + 1 ) ;
props. cl ( ) ;
} }
>
++ ++
< / button>
< button
onClick= { ( ) => {
setState ( ( pre) => pre - 1 ) ;
props. cl ( ) ;
} }
>
-- -
< / button>
< a> xxx< / a>
< / div>
) ;
}
export class App extends React . Component {
state = { message: "..." } ;
onBtnClick = ( ) => {
this . setState ( { message: this . state. message + "xx" } ) ;
} ;
render ( ) {
return (
< ShadowView>
< Axxx state= { this . state. message} cl= { this . onBtnClick} > < / Axxx>
< / ShadowView>
) ;
}
}
export default App;
主要是必须有一个shadowRoot,所以在每次更新时,会出现卸载问题,然后重新去给已有的shadowRoot附上shadow导致报错。在卸载时删掉即可。 至于样式,需要那种服务端渲染的样式写法,或者内联样式,否则就是样式隔离。 目前正常来说除了样式比较麻烦,事件状态什么的是都有的,等我再用一段时间看看还有啥问题。