Bra*_*ton 5 javascript google-chrome-extension shadow-dom reactjs material-ui
我正在构建一个Chrome扩展程序,该扩展程序使用Content脚本呈现一个React组件。React组件是一个工具栏,其中包含子工具,供用户在浏览页面时使用。我将Material UI用作工具栏及其所有其他子组件,弹出窗口等的组件库和样式解决方案。
使用div,“ Extension”作为mountNode,将根React组件注入页面即可。
content.js(Chrome内容脚本)
var app = $('<div id="Extension" style="position: fixed; display: block; bottom: 0px; left: 0px; width: 100vw; height: 48px; background: grey; z-index: 99999"></div>')
app.prependTo('body');
render(<App />, document.getElementById('Extension'))
Run Code Online (Sandbox Code Playgroud)
app.js(主要React组件)
Material UI还可以生成新的样式对象,并将css样式应用于页面上的子组件。所以这一切都很好
(资源)
const styles = {
root: {
display: "block",
color: "red",
},
};
Run Code Online (Sandbox Code Playgroud)
(生成)
.App-root-1 {
color: red;
display: block;
}
Run Code Online (Sandbox Code Playgroud)
由于我在Chrome中使用内容脚本,因此像Facebook这样的带有常规CSS选择器的网站会尝试覆盖中的样式Material UI。CSS属性也有可能从React工具栏泄漏到主页中。
我当前的解决方案是使用react-shadow围绕React组件的样式范围,并将其与页面的其余部分隔离。
var app = $('<div id="Extension" style="position: fixed; display: block; bottom: 0px; left: 0px; width: 100vw; height: 48px; background: grey; z-index: 99999"></div>')
app.prependTo('body');
render(<App />, document.getElementById('Extension'))
Run Code Online (Sandbox Code Playgroud)
当我这样做时,从“ Material-UI”生成的主题不适用于工具栏,而剩下的是将默认的内联样式应用于“ Extension” div(上面定义为content.js)。
主题是使用createMuiTheme(options)以下material-ui包生成的:
此功能成功,并且使用了以下主题来应用主题:
<MuiThemeProvider theme={theme}>
Run Code Online (Sandbox Code Playgroud)
我可以确认createMuiTheme(options)&<MuiThemeProvider/>
是否正常工作,因为主题的生成样式表被添加为页面标签中的最后一个标签<head>,如下图所示:
因为我的React工具栏元素位于#shadow-root内部,所以它无法从MUI生成的类中接收样式,因为它们包含在<head>主DOM树的主标记中。我相信,当<MuiThemeProvider/>被渲染,它追加其提供样式表的顶部主要 DOM树,不要将#影子根(其中,他们需要使样式本地应用)。见下图:
中的MUI样式表</head>,但需要将其移至#shadow-root
因此,我正在寻找一种解决方案,以将Material UI生成的样式表放置在#shadow-root下,以使它们在我的React工具栏组件上应用正确的样式。
1.)有什么方法可以<MuiThemeProvider/>使影子DOM 具有作用域,或在类名前加上诸如:host之类的前缀?
2.)有没有一种方法可以锁定由创建的#shadow-root react-shadow,以便在<MuiThemeProvider/>附加样式表时将其强制附加到shadow根?
3.)我对React,Javascript和创建Chrome扩展程序仍然缺乏经验。也许我已经错过了一个非常简单的解决方案?
任何帮助表示赞赏。
小智 8
我在打包 Web 应用程序以与另一个框架集成时遇到了同样的问题,这需要将我的 React 应用程序导出为 Web 组件。在与诸如此类的库挣扎了一段时间react-jss但运气不佳之后,我终于在今天早上遇到了@shawn-mclean 的Stack Overflow 答案。我在用头撞桌子的时候看到了你的问题,想传递对我有用的东西。
总之,我首先必须创建 Web 组件
WCRoot.js
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);
Run Code Online (Sandbox Code Playgroud)
接下来,我将 my 设置index.js为渲染<wc-component></wc-component>而不是<App />:
索引.js
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'));
Run Code Online (Sandbox Code Playgroud)
让我感到惊讶的一件事是我们根本不需要修改MuiThemeProvider...它只是获取StylesProvider. 我相信您应该能够修改content.js为如下所示:
内容.js
var app = $('<div id="Extension" style="position: fixed; display: block; bottom: 0px; left: 0px; width: 100vw; height: 48px; background: grey; z-index: 99999"></div>')
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);
Run Code Online (Sandbox Code Playgroud)