共计 2549 个字符,预计需要花费 7 分钟才能阅读完成。
react-webcomponentify 是一个能够无需任何额定工作量就能将 react 组件打包 导出为 webComponent 的库。整个库在 gizp 之后仅有 1.5kb。
应用办法
根底
import React from "react";
import {registerAsWebComponent} from "react-webcomponentify";
export const ExampleReactComponent = () => {return <div> Hello </div>;};
registerAsWebComponent(ExampleReactComponent, "example-component");
html
<!DOCTYPE html>
<html>
....
<body>
<example-component />
</body>
....
</html>
进阶
向 react 传递数据:能够通过 html 的 attributes 传递字符串属性,通过 setProps 办法传递函数或者对象之类的属性
import React from "react";
import {registerAsWebComponent} from "react-webcomponentify";
export const ButtonComponent = props => {
return (
<div>
Hello <button onClick={props.onClick}>{props.text}</button>
</div>
);
};
registerAsWebComponent(ButtonComponent, "button-web");
html
<!DOCTYPE html>
<html>
....
<body>
<button-web text="click me" id="mybutton" />
</body>
....
<script>
const myBtn = document.getElementById("mybutton");
myBtn.setProps({onClick: () => console.log("btn was clicked")
});
</script>
</html>
每一个通过 react-webcomponentify 创立的自定义组件都有一个 setProps
实例办法
element.setProps({
....
/* 在这里设置你想要发送给 react 的属性 */
....
})
同样反对子组件
import React from "react";
import {registerAsWebComponent} from "react-webcomponentify";
// You access the children just like you would in react (using this.props.children)
export const ComponentWithChild = props => {
return (
<div>
Hello World
{this.props.text}
<div>{this.props.children}</div>
</div>
);
};
registerAsWebComponent(ComponentWithChild, "component-with-child");
html
<!DOCTYPE html>
<html>
....
<body>
<component-with-child text="I love children">
<p>Some child</p>
</component-with-child>
</body>
....
</html>
原理剖析
1. 创立工程函数,应用 customElements 定义 webcomponent,通过 ShadowDom 隔离组件
2. 在类的构造函数中获取 html 标签的所有属性。定义一个 MutationObserver 监听属性的变动。调用 renderReact2Node 办法
3.renderReact2Node 办法作用是将 react 组件挂载到页面上。接管的参数有要导出的 react 组件、初始化数据(就是第 2 步获取到的属性)、指标父容器元素(就是第 1 步创立的 shandowDom)、onRender 回调。
4. 在 renderReact2Node 中定义一个高阶组件 PropBridge,作用是保护 state 状态,而后将该组件 ref 导出。挂载。
这样在 shadowDom 中通过调用 ref.current.setProps 就实现了通信。
class PropBridge extends React.PureComponent {state = { ...initialProps};
setProps = (props: React.RefObject<PropBridge>) =>
this.setState(() => props);
render() {return <RComponent {...this.props} {...this.state} />;
}
}
const propBridgeRef = createRef<PropBridge>();
ReactDOM.render(<PropBridge ref={propBridgeRef} />, targetDomNode, () =>
onRender(propBridgeRef)
);
5. 在容器的 MutationObserver 的回调中调用 setProps。这样就实现了批改标签属性实时通信给 react
6. 在容器创立一个实例办法 setProps,对参数进行解决后调用 PropBridge 的 setProps,这样就实现了简单数据类型的传递。
注意事项
我在应用过程中遇到一个大坑。react 组件 webpack 导出的时候进行了分包。援用组件的 angular 我的项目也应用的 webpack。也进行了分包,所以 react 组件引入的时候,呈现了 bundle 错乱的问题。
起因是两份 webpack 配置外面 output.jsonpFunction 没有写,默认是 window 下的一个全局变量 webpackJsonp。
解决办法
1.react 导出不分包
2. 批改 react webpack 的 jsonpFunction。(在 webpack5 中叫 chunkLoadingGlobal)