跳到内容
+

覆盖组件结构

了解如何覆盖 Material UI 组件的默认 DOM 结构。

Material UI 组件旨在适应最广泛的用例,但您有时可能需要更改组件结构在 DOM 中的渲染方式。

要理解如何做到这一点,了解 API 设计随时间演变的历程,并对组件本身有一个准确的心智模型会有所帮助。

背景

在 Material UI v6 之前,无法覆盖库中大多数组件的结构。某些组件具有 *Props props,允许您将 props 传递给特定插槽,但这种模式并未得到一致的应用。

在 v6 中,这些 props 已被弃用,转而使用 slotsslotProps props,这些 props 可以更精细地控制组件的结构,并使整个库的 API 更加一致。

心智模型

组件的结构由填充该组件插槽的元素决定。插槽最常由 HTML 标签填充,但也可能由 React 组件填充。

所有组件都包含一个根插槽,用于定义它们在 DOM 树中的主要节点;更复杂的组件还包含额外的内部插槽,这些插槽以它们所代表的元素命名。

所有非实用程序 Material UI 组件都接受两个 props 来覆盖其渲染的 HTML 结构

  • component—覆盖根插槽
  • slots—替换任何内部插槽(如果存在)以及根插槽

此外,您可以使用 slotProps 将自定义 props 传递给内部插槽。

根插槽

根插槽表示组件的最外层元素。它由带有适当 HTML 元素的样式化组件填充。

例如,Button 的根插槽是一个 <button> 元素。此组件具有一个根插槽;更复杂的组件可能具有额外的内部插槽

component prop

使用 component prop 覆盖组件的根插槽。下面的演示展示了如何将 Button 的 <button> 标签替换为 <a> 以创建链接按钮

Enter 开始编辑

内部插槽

复杂组件由一个或多个内部插槽以及根插槽组成。这些插槽通常(但并非总是)嵌套在根插槽内。

例如,Autocomplete 由一个根 <div> 组成,该根 <div> 包含多个内部插槽,这些插槽以它们所代表的元素命名:input、startDecorator、endDecorator、clearIndicator、popupIndicator 等。

slots prop

使用 slots prop 替换组件的内部插槽。下面的示例展示了如何替换 Autocomplete 组件中的 popper 插槽以删除弹出功能

Enter 开始编辑

slotProps prop

slotProps prop 是一个对象,其中包含组件内所有插槽的 props。您可以使用它来定义要传递给组件内部插槽的其他自定义 props。

例如,下面的代码片段展示了如何将自定义 data-testid 添加到 Autocomplete 组件的 popper 插槽

<Autocomplete slotProps={{ popper: { 'data-testid': 'my-popper' } }} />

放置在主组件上的所有其他 props 也将传播到根插槽中(就像它们放置在 slotProps.root 中一样)。以下两个示例是等效的

<Autocomplete id="badge1">
<Autocomplete slotProps={{ root: { id: 'badge1' } }}>

最佳实践

当您需要覆盖元素同时保留插槽的样式时,请使用 componentslotProps.{slot}.component prop。

当您需要使用自定义组件替换插槽的样式和功能时,请使用 slots prop。

使用 component 进行覆盖可让您将该元素的属性直接应用于根元素。例如,如果您使用 <li> 标签覆盖 Button 的根元素,则可以直接将 <li> 属性 value 添加到组件。如果您对 slots.root 执行相同的操作,则需要将此属性放在 slotProps.root 对象上,以避免 TypeScript 错误。

在覆盖更复杂组件的插槽时,请注意您渲染的 DOM 结构。如果您过度偏离默认结构,很容易破坏语义化和可访问 HTML 的规则——例如,无意中将块级元素嵌套在内联元素内部。