如何为React定制元素中MUI材质v5创建插入点以在阴影DOM中安装样式 [英] How to create insertion point to mount styles in shadow dom for MUI material v5 in React custom element

查看:7
本文介绍了如何为React定制元素中MUI材质v5创建插入点以在阴影DOM中安装样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用@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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆