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)