React component's Material UI theme not scoped locally to Shadow DOM
我正在构建一个Chrome扩展程序,该扩展程序使用Content脚本呈现一个React组件。 React组件是一个工具栏,其中包含子工具,供用户在浏览页面时使用。我将Material UI用作工具栏及其所有其他子组件,弹出窗口等的组件库和样式解决方案。
什么有效
使用div," Extension"作为mountNode,将根React组件注入页面即可。
content.js(Chrome内容脚本)
1 2 3 | var app = $('') app.prependTo('body'); render(<App />, document.getElementById('Extension')) |
app.js(主要React组件)
(资源)
1 2 3 4 5 6 | const styles = { root: { display:"block", color:"red", }, }; |
(生成)
1 2 3 4 | .App-root-1 { color: red; display: block; } |
问题
由于我在chrome中使用内容脚本,因此具有常规css选择器的Facebook之类的网站会尝试覆盖
中途解决方案
我当前的解决方案是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import React from"react"; import PropTypes from 'prop-types'; import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles'; import ShadowDOM from 'react-shadow'; import ToolBar from './ToolBar' const theme = createMuiTheme({ palette: { primary: { main: '#ef5350', }, type: 'light' }, status: { danger: 'orange', }, }); const styles = { root: { display:"block", color:"red", }, }; class App extends React.Component { constructor(props) { super(props); this.state = { open: false } } render () { const { classes } = this.props; return ( <ShadowDOM> <MuiThemeProvider theme={theme}> <ToolBar /> </MuiThemeProvider> </ShadowDOM> ) } }; App.propTypes = { classes: PropTypes.object, }; export default withStyles(styles)(App) |
当我这样做时," Material-UI"生成的主题不适用于工具栏,剩下的是默认的行内样式应用于" Extension" div(上面定义为content.js)。
使用
此功能成功,并且使用了以下主题来应用主题:
1 | <MuiThemeProvider theme={theme}> |
我可以确认
之所以起作用,是因为主题的生成的样式表被添加为页面
我需要发生什么
因为我的React工具栏元素位于#shadow-root内部,所以它无法从MUI生成的类中接收样式,因为它们包含在主DOM树的主
因此,我正在寻找一种解决方案,以将Material UI生成的样式表放置在#shadow-root下,以便它们在我的React工具栏组件上应用正确的样式。
1.)是否可以通过
2.)是否有办法锁定由
3.)我仍然对React,Javascript和创建Chrome扩展程序缺乏经验。也许我已经错过了一个非常简单的解决方案?
任何帮助表示赞赏。
我在打包Web应用程序以与另一个框架集成时遇到了同样的问题,这要求将React应用程序导出为Web组件。在像
总而言之,我首先必须创建Web组件
WCRoot.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import React from 'react'; import ReactDOM from 'react-dom'; import { StylesProvider, jssPreset } from '@material-ui/styles'; import { create } from 'jss'; import App from './App'; class WCRoot extends HTMLElement { connectedCallback() { const shadowRoot = this.attachShadow({ mode: 'open' }); const mountPoint = document.createElement('span'); // first we need to store a reference to an element INSIDE of the shadow root const reactRoot = shadowRoot.appendChild(mountPoint); // now we use that saved reference to create a JSS configuration const jss = create({ ...jssPreset(), insertionPoint: reactRoot }); // finally we need to wrap our application in a StylesProvider ReactDOM.render( <StylesProvider jss={jss}> <App /> </StylesProvider>, mountPoint); } } customElements.define('wc-root', WCRoot); |
接下来,我将
index.js
1 2 3 4 5 6 7 | import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; // eslint-disable-next-line import WCRoot from './WCRoot'; ReactDOM.render(<wc-root></wc-root>, document.getElementById('root')); |
让我感到惊讶的是,我们根本不需要修改
content.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var app = $('') app.prependTo('body'); var shadowRoot = this.attachShadow({ mode: 'open' }); var mountPoint = document.getElementById('Extension'); var reactRoot = shadowRoot.appendChild(mountPoint); // see code blocks above for the import statements for `create` and `jssPreset` var jss = create({ ...jssPreset(), insertionPoint: reactRoot }); render( <StylesProvider jss={jss}> <App /> </StylesProvider>, mountPoint); |
您可能需要查看ShadowDOM的
像这样使用(示例来自其github):
1 2 3 | <ShadowDOM include={['css/core/calendar.css', props.theme]}> Calendar for {props.date} </ShadowDOM> |