【React】react-shadow原理(shadow-dom的探索)

前言

  • 突然对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导致报错。在卸载时删掉即可。
  • 至于样式,需要那种服务端渲染的样式写法,或者内联样式,否则就是样式隔离。
  • 目前正常来说除了样式比较麻烦,事件状态什么的是都有的,等我再用一段时间看看还有啥问题。

猜你喜欢

转载自blog.csdn.net/yehuozhili/article/details/117393922