如何为React定制元素中MUI材质v5创建插入点以在阴影DOM中安装样式 [英] How to create insertion point to mount styles in shadow dom for MUI material v5 in React custom element
问题描述
使用@Material-UI/core V4(准确地说是4.12.3),我使用webpack和巴别塔成功地创建了一个定制元素。我过去常常使用@Material-UI/core Make Styles来设计它的样式。现在我正在升级到@Mui/Material v5,并希望使用来自@Mui/Material的内置组件,但它们不会在定制元素中显示为样式。 请注意,我需要这是一个自定义元素,因为它将集成到另一个托管应用程序中。
v4中之前的index.tsx
import AppComponent from './App';
import { render } from 'react-dom';
import { StylesProvider, jssPreset } from '@material-ui/core/styles';
import { create } from 'jss';
class MyWebComponent extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' });
const mountPoint = document.createElement('custom-jss-insertion-point');
const reactRoot = shadowRoot.appendChild(mountPoint);
const jss = create({
...jssPreset(),
insertionPoint: reactRoot,
});
render(
<StylesProvider jss={jss}>
<AppComponent />
</StylesProvider>,
mountPoint
);
}
}
customElements.define('my-element', MyWebComponent);
升级到@mui/Material v5(准确地说是v5.0.4),我首先尝试使用StyledEngineProvider来挂载样式。然后我尝试了@Mui/Style jssPreset。这两种方法都行不通。我所说的不起作用的意思是,AppComponent引用的DataContainer有@Mui/Material组件,并且它们都是在没有任何样式(如Grid、Button、InputLabel、Select等)的情况下加载的。
第一次尝试使用StyledEngineering Provider
import AppComponent from './App';
import { ThemeProvider, createTheme, StyledEngineProvider } from '@mui/material/styles';
import { render } from 'react-dom';
const theme = createTheme();
class MyWebComponent extends HTMLElement {
connectedCallback() {
// can't use jss in mui v5
const shadowRoot = this.attachShadow({ mode: 'open' });
const mountPoint = document.createElement('custom-insertion-point');
const reactRoot = shadowRoot.appendChild(mountPoint);
render(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<AppComponent />
</ThemeProvider>
</StyledEngineProvider>,
mountPoint //I have also used reactRoot here instead and got same result
);
}
}
customElements.define('my-element', MyWebComponent);
再次尝试@Mui/Style jssPreset
import AppComponent from './App';
import { render } from 'react-dom';
import { StylesProvider, jssPreset } from '@mui/styles';
import { create } from 'jss';
class MyWebComponent extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' });
const mountPoint = document.getElementById('jss-insertion-point');
const reactRoot = shadowRoot.appendChild(mountPoint);
const jss = create({
...jssPreset(),
insertionPoint: reactRoot,
});
render(
<StylesProvider jss={jss}>
<AppComponent />
</StylesProvider>,
mountPoint
);
}
}
customElements.define('my-element', MyWebComponent);
AppComponent
import React from 'react';
import { Suspense } from 'react';
import DataContainer from './components/DataContainer';
class AppComponent extends React.Component<any> {
render() {
return (
<Suspense fallback='Loading...'>
<div className='AppComponent'>
<DataContainer />
</div>
</Suspense>
);
}
}
export default AppComponent;
数据容器
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
export default function FullWidthGrid() {
return (
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={2}>
<Grid item xs={6} md={8}>
<Button variant="contained">xs=6 md=8</Button>
</Grid>
<Grid item xs={6} md={4}>
<Item>xs=6 md=4</Item>
</Grid>
<Grid item xs={6} md={4}>
<Item>xs=6 md=4</Item>
</Grid>
<Grid item xs={6} md={8}>
<Item>xs=6 md=8</Item>
</Grid>
</Grid>
<div>
<FormControl sx={{ m: 1, minWidth: 180 }}>
<Select autoWidth>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Twenty</MenuItem>
<MenuItem value={21}>Twenty one</MenuItem>
<MenuItem value={22}>Twenty one and a half</MenuItem>
</Select>
</FormControl>
</div>
</Box>
);
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" />
<title>React Custom Element</title>
</head>
<body>
<my-element id="elem"> </my-element>
</body>
</html>
这是我看到的:
这就是我在这个堆栈闪电战中应该看到的。(请注意,不幸的是,我无法使用自定义元素创建Stackblitz) https://stackblitz.com/edit/react-d8xtdu?file=index.js
推荐答案
我会这样做:
需要创建style
标签。这将是插入限定作用域的阴影DOM样式的情感(材质UI 5样式解决方案)的入口点。
下一步是配置JSS和情感缓存
const jss = create({
...jssPreset(),
insertionPoint: reactRoot,
});
const cache = createCache({
key: 'css',
prepend: true,
container: emotionRoot,
});
最后要做的是将树包装在提供程序中
render(
<StylesProvider jss={jss}>
<CacheProvider value={cache}>
<ThemeProvider theme={theme}>
<Demo />
</ThemeProvider>
</CacheProvider>
</StylesProvider>,
mountPoint
);
完整示例:
import React from 'react';
import Demo from './demo';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { StylesProvider, jssPreset } from '@mui/styles';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { create } from 'jss';
import { render } from 'react-dom';
const theme = createTheme();
class MyWebComponent extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: 'open' });
const emotionRoot = document.createElement('style');
const mountPoint = document.createElement('div');
shadowRoot.appendChild(emotionRoot);
const reactRoot = shadowRoot.appendChild(mountPoint);
const jss = create({
...jssPreset(),
insertionPoint: reactRoot,
});
const cache = createCache({
key: 'css',
prepend: true,
container: emotionRoot,
});
render(
<StylesProvider jss={jss}>
<CacheProvider value={cache}>
<ThemeProvider theme={theme}>
<Demo />
</ThemeProvider>
</CacheProvider>
</StylesProvider>,
mountPoint
);
}
}
if (!customElements.get('my-element')) {
customElements.define('my-element', MyWebComponent);
}
这篇关于如何为React定制元素中MUI材质v5创建插入点以在阴影DOM中安装样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!