跳到主要內容
+

常見問題

遇到特定的問題嗎?先查看常見問題中的這些常見陷阱。

如果您仍然找不到您要尋找的內容,您可以參考我們的支援頁面

MUI 是一個很棒的組織。我該如何支持它?

有很多種方式可以支持我們

  • 口耳相傳。透過在您的網站上連結到 mui.com 來宣傳 MUI 的產品——每個反向連結都很重要。在 X 上追蹤我們,按讚並轉發重要新聞。或者只是和您的朋友們談論我們。
  • 給予我們回饋。告訴我們哪些方面做得好,或者哪些方面有改進的機會。請對您最感興趣解決的問題投贊成票 (👍)。
  • 幫助新用戶。您可以在 Stack Overflow 上回答問題。
  • 讓改變發生.
  • Open Collective 上給予我們財務支持。如果您在商業專案中使用 Material UI,並希望透過成為贊助商來支持其持續開發,或者在副專案或興趣專案中希望成為支持者,您可以透過 Open Collective 來做到這一點。所有捐款都以透明的方式管理,贊助商會在 README 和首頁上獲得表彰。

為什麼在模組視窗開啟時,固定定位的元素會移動?

一旦模組視窗開啟,捲動就會被封鎖。這可以防止在模組視窗應該是唯一互動內容時與背景互動。但是,移除捲軸可能會使您的固定定位元素移動。在這種情況下,您可以套用全域 .mui-fixed 類別名稱,以告知 Material UI 處理這些元素。

我該如何全域停用漣漪效果?

漣漪效果完全來自 BaseButton 元件。您可以透過在您的主題中提供以下內容來全域停用漣漪效果

import { createTheme } from '@mui/material';

const theme = createTheme({
  components: {
    // Name of the component ⚛️
    MuiButtonBase: {
      defaultProps: {
        // The props to apply
        disableRipple: true, // No more ripple, on the whole application 💣!
      },
    },
  },
});

我該如何全域停用轉場效果?

Material UI 使用相同的主題輔助程式來建立其所有轉場效果。因此,您可以透過覆寫主題中的輔助程式來停用所有轉場效果

import { createTheme } from '@mui/material';

const theme = createTheme({
  transitions: {
    // So `transition: none;` gets applied everywhere
    create: () => 'none',
  },
});

在視覺測試期間停用轉場效果,或提高低階裝置上的效能可能會很有用。

您可以更進一步停用所有轉場效果和動畫效果

import { createTheme } from '@mui/material';

const theme = createTheme({
  components: {
    // Name of the component ⚛️
    MuiCssBaseline: {
      styleOverrides: {
        '*, *::before, *::after': {
          transition: 'none !important',
          animation: 'none !important',
        },
      },
    },
  },
});

請注意,上述方法需要使用 CssBaseline。如果您選擇不使用它,您仍然可以透過包含這些 CSS 規則來停用轉場效果和動畫效果

*,
*::before,
*::after {
  transition: 'none !important';
  animation: 'none !important';
}

我必須使用 Emotion 來設定我的應用程式樣式嗎?

不,這不是必需的。但是,如果您使用的是預設樣式引擎 (@mui/styled-engine),則 Emotion 相依性已內建,因此不會增加額外的套件大小負擔。

也許,但是,您正在將一些 Material UI 元件新增到已經使用另一個樣式解決方案的應用程式,或者已經熟悉不同的 API,並且不想學習新的 API?在這種情況下,請前往樣式庫互通性章節,以了解如何使用替代樣式庫重新設定 Material UI 元件的樣式。

我應該在何時使用內嵌樣式與 CSS?

作為經驗法則,僅將內嵌樣式用於動態樣式屬性。CSS 替代方案提供了更多優勢,例如

  • 自動加上前綴
  • 更好的偵錯
  • 媒體查詢
  • 關鍵影格

我該如何使用 react-router?

請造訪關於與第三方路由庫整合的指南,例如 react-router 或 Next.js,以取得更多詳細資訊。

我該如何存取 DOM 元素?

所有應在 DOM 中呈現某些內容的 Material UI 元件都會將其 ref 轉發到基礎 DOM 元件。這表示您可以透過讀取附加到 Material UI 元件的 ref 來取得 DOM 元素

// or a ref setter function
const ref = React.createRef();
// render
<Button ref={ref} />;
// usage
const element = ref.current;

如果您不確定有問題的 Material UI 元件是否轉發其 ref,您可以查看「Props」下的 API 文件。您應該會找到如下訊息,就像在 Button API 中一樣。

ref 會轉發到根元素。

我的應用程式在伺服器上無法正確呈現

如果它無法運作,在 99% 的情況下,這都是組態問題。遺失的屬性、錯誤的呼叫順序或遺失的元件 – 伺服器端渲染對於組態要求嚴格。

找出問題所在的最佳方法是將您的專案與已經正常運作的設定進行比較。逐步查看參考實作

為什麼我看到的顏色與我在這裡看到的顏色不同?

文件網站正在使用自訂主題。因此,色彩調色盤與 Material UI 隨附的預設主題不同。請參考此頁面以了解有關主題客製化的資訊。

為什麼元件 X 需要 prop 中的 DOM 節點而不是 ref 物件?

諸如 PortalPopper 之類的元件分別需要在 containeranchorEl prop 中使用 DOM 節點。看起來似乎很方便地在這些 props 中簡單地傳遞 ref 物件,並讓 Material UI 存取當前值。

這在簡單的情況下有效

function App() {
  const container = React.useRef(null);

  return (
    <div className="App">
      <Portal container={container}>
        <span>portaled children</span>
      </Portal>
      <div ref={container} />
    </div>
  );
}

其中 Portal 只會在 container.current 可用時將子項掛載到容器中。以下是 Portal 的簡單實作

function Portal({ children, container }) {
  const [node, setNode] = React.useState(null);

  React.useEffect(() => {
    setNode(container.current);
  }, [container]);

  if (node === null) {
    return null;
  }
  return ReactDOM.createPortal(children, node);
}

使用這種簡單的啟發式方法,Portal 可能會在掛載後重新渲染,因為 refs 在任何效果執行之前都是最新的。但是,僅僅因為 ref 是最新的,並不表示它指向已定義的實例。如果 ref 附加到 ref 轉發元件,則不清楚 DOM 節點何時可用。在上面的範例中,Portal 將執行一次效果,但可能不會重新渲染,因為 ref.current 仍然是 null。對於 Suspense 中的 React.lazy 元件,這尤其明顯。上述實作也可能無法說明 DOM 節點的變更。

這就是為什麼 prop 需要實際的 DOM 節點,以便 React 可以負責決定何時應該重新渲染 Portal

function App() {
  const [container, setContainer] = React.useState(null);
  const handleRef = React.useCallback(
    (instance) => setContainer(instance),
    [setContainer],
  );

  return (
    <div className="App">
      <Portal container={container}>
        <span>Portaled</span>
      </Portal>
      <div ref={handleRef} />
    </div>
  );
}

clsx 相依性是做什麼用的?

clsx 是一個微小的實用程式,用於有條件地建構 className 字串,從物件中取出類別字串作為鍵,布林值作為值。

您可以不用寫

// let disabled = false, selected = true;

return (
  <div
    className={`MuiButton-root ${disabled ? 'Mui-disabled' : ''} ${
      selected ? 'Mui-selected' : ''
    }`}
  />
);

您可以這樣做

import clsx from 'clsx';

return (
  <div
    className={clsx('MuiButton-root', {
      'Mui-disabled': disabled,
      'Mui-selected': selected,
    })}
  />
);

我無法在 styled() 實用程式中使用元件作為選取器。我該怎麼辦?

如果您收到錯誤訊息:TypeError: Cannot convert a Symbol value to a string,請查看 styled() 文件頁面,以取得有關如何修正此問題的指示。

我該如何為免費範本做出貢獻?

範本是使用共用主題建置的。以下是建立新範本的結構

範本頁面

docs/pages/material-ui/getting-started/templates/<name>.js 目錄中建立一個新頁面,其中包含以下程式碼

import * as React from 'react';
import AppTheme from 'docs/src/modules/components/AppTheme';
import TemplateFrame from 'docs/src/modules/components/TemplateFrame';
import Template from 'docs/data/material/getting-started/templates/<name>/<Template>';

export default function Page() {
  return (
    <AppTheme>
      <TemplateFrame>
        <Template />
      </TemplateFrame>
    </AppTheme>
  );
}

然後在 docs/data/material/getting-started/templates/<name>/<Template>.tsx 建立範本檔案(如果需要,新增更多檔案)

注意:<Template> 必須是 <name> 資料夾的 PascalCase 字串。

共用主題

範本必須使用來自 ../shared-theme/AppThemeAppTheme,以確保所有範本的外觀和風格一致。

如果範本包含自訂主題元件,例如具有 MUI X 主題元件的儀表板範本,請將它們傳遞給 AppThemethemedComponents prop

import AppTheme from '../shared-theme/AppTheme';

const xThemeComponents = {
  ...chartsCustomizations,
  ...dataGridCustomizations,
  ...datePickersCustomizations,
  ...treeViewCustomizations,
};

export default function Dashboard(props: { disableCustomTheme?: boolean }) {
  return (
    <AppTheme {...props} themeComponents={xThemeComponents}>...</AppTheme>
  )
}

色彩模式切換

共用主題提供 2 種色彩模式切換外觀,ColorModeSelectColorModeIconDropdown。您可以在範本中使用其中任何一種,它將隱藏在 TemplateFrame 中,但在 CodeSandbox 和 StackBlitz 中可見。

範本框架

如果範本具有需要固定在頂部的側邊欄或標頭,請參考 CSS 變數 --template-frame-height 進行調整。

例如,儀表板範本具有需要考慮範本框架高度的固定標頭

<AppBar
  position="fixed"
  sx={{
    top: 'var(--template-frame-height, 0px)',
    // ...other styles
  }}
>

這將使 AppBar 在預覽模式中保持在 TemplateFrame 下方,但在 CodeSandbox 和 StackBlitz 中固定在頂部。

[舊版] 我在頁面上有數個樣式實例

如果您在主控台中看到類似於以下的警告訊息,則您可能在頁面上初始化了數個 @mui/styles 實例。

可能的原因

發生這種情況有幾個常見原因

  • 您的相依性中的某處有另一個 @mui/styles 程式庫。
  • 您的專案具有 monorepo 結構(例如,lerna 或 yarn workspaces),並且 @mui/styles 模組在多個套件中都是相依性(這或多或少與前一個相同)。
  • 您有數個正在同一頁面上執行的應用程式正在使用 @mui/styles(例如,webpack 中的數個進入點已載入到同一頁面上)。

node_modules 中的重複模組

如果您認為問題可能出在 @mui/styles 模組在您的相依性中的某處重複,則有多種方法可以檢查這一點。您可以在您的應用程式資料夾中使用 npm ls @mui/stylesyarn list @mui/stylesfind -L ./node_modules | grep /@mui/styles/package.json 命令。

如果這些命令都沒有識別出重複項,請嘗試分析您的套件中是否有 @mui/styles 的多個實例。您可以只檢查您的套件來源,或使用諸如 source-map-explorerwebpack-bundle-analyzer 之類的工具。

如果您確定重複是您遇到的問題,則可以嘗試幾種方法來解決它

如果您使用的是 npm,您可以嘗試執行 npm dedupe。此命令會搜尋本機相依性,並嘗試透過將常見相依性進一步向上移動樹狀結構來簡化結構。

如果您使用的是 webpack,您可以變更它解析 @mui/styles 模組的方式。您可以覆寫 webpack 將尋找您的相依性的預設順序,並使您的應用程式 node_modules 比預設節點模組解析順序更優先

 resolve: {
+  alias: {
+    '@mui/styles': path.resolve(appFolder, 'node_modules', '@mui/styles'),
+  },
 },

在一個頁面上執行多個應用程式

如果您在一個頁面上執行數個應用程式,請考慮對所有應用程式使用一個 @mui/styles 模組。如果您使用的是 webpack,則可以使用 CommonsChunkPlugin 來建立明確的 vendor chunk,其中將包含 @mui/styles 模組

  module.exports = {
    entry: {
+     vendor: ['@mui/styles'],
      app1: './src/app.1.js',
      app2: './src/app.2.js',
    },
    plugins: [
+     new webpack.optimize.CommonsChunkPlugin({
+       name: 'vendor',
+       minChunks: Infinity,
+     }),
    ]
  }

[舊版] 為什麼我的元件在生產版本中無法正確呈現?

發生這種情況的首要原因很可能是由於您的程式碼在生產套件中時類別名稱衝突。為了使 Material UI 能夠運作,頁面上所有元件的 className 值都必須由 類別名稱產生器的單一實例產生。

為了修正此問題,需要初始化頁面上的所有元件,以便它們之間只有永遠一個類別名稱產生器

您可能會在各種情況下意外地使用兩個類別名稱產生器

  • 您不小心套件了兩個版本的 @mui/styles。您的相依性可能未正確地將 Material UI 設定為對等相依性。
  • 您正在對 React 樹狀結構的子集使用 StylesProvider
  • 您正在使用套件工具,並且它以導致建立多個類別名稱產生器實例的方式分割程式碼。

總體而言,透過使用 StylesProvider 元件包裝每個 Material UI 應用程式,在其元件樹狀結構的頂端並使用它們之間共用的單一類別名稱產生器,可以輕鬆地從此問題中恢復。

[舊版] CSS 僅在第一次載入時運作,然後就消失了

CSS 僅在頁面的第一次載入時產生。然後,CSS 在伺服器上針對連續請求遺失。

應採取的行動

樣式解決方案依賴快取,即樣式表管理器,來僅針對每個元件類型注入一次 CSS(如果您使用兩個按鈕,則只需要按鈕的 CSS 一次)。您需要為每個請求建立新的 sheets 實例

修正範例

-// Create a sheets instance.
-const sheets = new ServerStyleSheets();

 function handleRender(req, res) {
+  // Create a sheets instance.
+  const sheets = new ServerStyleSheets();

   //…

   // Render the component to a string.
   const html = ReactDOMServer.renderToString(

[舊版] React 類別名稱 hydration 不符

用戶端和伺服器之間存在類別名稱不符的情況。它可能適用於第一個請求。另一個徵兆是樣式在初始頁面載入與用戶端腳本下載之間發生變化。

應採取的行動

類別名稱值依賴於類別名稱產生器的概念。整個頁面需要使用單一產生器進行渲染。此產生器需要在伺服器和用戶端上的行為完全相同。例如

  • 您需要為每個請求提供新的類別名稱產生器。但是您不應在不同請求之間共用 createGenerateClassName()

    修正範例

    -// Create a new class name generator.
    -const generateClassName = createGenerateClassName();
    
     function handleRender(req, res) {
    +  // Create a new class name generator.
    +  const generateClassName = createGenerateClassName();
    
       //…
    
       // Render the component to a string.
       const html = ReactDOMServer.renderToString(
    
  • 您需要驗證您的用戶端和伺服器是否正在執行完全相同的版本的 Material UI。即使是次要版本的不符也可能會導致樣式問題。若要檢查版本號碼,請在您建置應用程式的環境以及您的部署環境中執行 npm list @mui/styles

    您也可以透過在 package.json 的相依性中指定特定的 Material UI 版本來確保不同環境中的版本相同。

    修正範例 (package.json)

      "dependencies": {
        ...
    -   "@mui/styles": "^5.0.0",
    +   "@mui/styles": "5.0.0",
        ...
      },
    
  • 您需要確保伺服器和用戶端共用相同的 process.env.NODE_ENV 值。