跳到内容
+

Shadow DOM

Shadow DOM 允许你封装应用程序的各个部分,使其与针对常规 DOM 树的全局样式分隔开。

如何在 Material UI 中使用 Shadow DOM

1. 样式

Shadow DOM 是一种 API,它提供了一种将隐藏的、隔离的 DOM 附加到元素的方法。当您需要将不同组件的结构、样式和行为与页面上其余代码分开,以防止冲突时,这非常有用。请参阅 关于 Shadow DOM 的 MDN 文档 以获取更多信息。以下代码片段展示了如何在 Shadow DOM 内部应用样式

const container = document.querySelector('#root');
const shadowContainer = container.attachShadow({ mode: 'open' });
const shadowRootElement = document.createElement('div');
shadowContainer.appendChild(shadowRootElement);

const cache = createCache({
  key: 'css',
  prepend: true,
  container: shadowContainer,
});

ReactDOM.createRoot(shadowRootElement).render(
  <CacheProvider value={cache}>
    <App />
  </CacheProvider>,
);

2. 主题

Material UI 组件(如 Menu、Dialog、Popover 等)使用 MUI Base Portal 组件在当前 DOM 层次结构之外的容器中渲染新的“子树”。默认情况下,此容器是 document.body。但是由于样式仅在 Shadow DOM 内部应用,因此我们需要在 Shadow DOM 容器内部渲染 portal

const theme = createTheme({
  components: {
    MuiPopover: {
      defaultProps: {
        container: shadowRootElement,
      },
    },
    MuiPopper: {
      defaultProps: {
        container: shadowRootElement,
      },
    },
    MuiModal: {
      defaultProps: {
        container: shadowRootElement,
      },
    },
  },
});

// ...

<ThemeProvider theme={theme}>
  <App />
</ThemeProvider>;

3. CSS 主题变量(可选)

要在 Shadow DOM 内部使用 CSS 主题变量,您需要设置用于生成 CSS 变量的选择器

 const theme = createTheme({
+  cssVariables: {
+    rootSelector: ':host',
+    colorSchemeSelector: 'class',
+  },
   components: {
     // ...same as above steps
   }
 })

最后,使用步骤 1 中的 shadowRootElement 作为值,设置 colorSchemeNode 属性

 <ThemeProvider
   theme={theme}
+  colorSchemeNode={shadowRootElement}
 >

演示

在下面的示例中,您可以看到 shadow DOM 外部的组件受全局样式影响,而 shadow DOM 内部的组件则不受影响