gpt4 book ai didi

reactjs - 如何在 React 自定义元素中为 MUI Material v5 创建插入点以在 shadow dom 中挂载样式

转载 作者:行者123 更新时间:2023-12-05 04:42:36 25 4
gpt4 key购买 nike

使用 @material-ui/core V4(准确地说是 4.12.3)我有一个使用 webpack 和 babel 成功创建的自定义元素。我曾经使用 @material-ui/core makeStyles 来设计它的样式。现在我正在升级到 @mui/material v5 并想使用来自 @mui/material 的内置组件,但它们不会在自定义元素中显示样式。请注意,我需要这是一个自定义元素,因为它将集成到另一个托管应用程序中。

index.tsx 在 v4 之前

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/styles jssPreset。无论哪种方式都行不通。我所说的不起作用是指 AppComponent 引用的 DataContainer 具有 @mui/material 组件,并且它们都在加载时没有任何样式(例如 Grid、Button、InputLabel、Select 等等)。

首先尝试使用 StyledEngineProvider

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/styles 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);

应用组件

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>

这是我看到的:

enter image description here

这就是我应该看到的,如本次 stackblitz 所示。 (请注意,不幸的是我无法创建带有自定义元素的 stackblitz) https://stackblitz.com/edit/react-d8xtdu?file=index.js

enter image description here

最佳答案

下面是我的做法:

您需要创建style 标签。这将是插入作用域阴影 DOM 样式的情感( Material 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);
}

关于reactjs - 如何在 React 自定义元素中为 MUI Material v5 创建插入点以在 shadow dom 中挂载样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69813276/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com