Material UI in React [ Day 28 ] Customization Component 自订组件 (part1)

由於组件可以在不同的context中使用,有几种方法可以解决这个问题,官方连结

  • 1.一次性情况的特定变化
  • 2.一次性情况的动态变化
  • 3.在不同context中重用的组件的特定变体
  • 4.Material Design 变体,例如按钮组件
  • 5.Global theme

1. 一次性情况的特定变化

你可能需要为特定实现更改组件的样式,为此可以使用以下解决方案:

用 className 覆盖样式

每个组件都提供一个 className 属性,该属性始终应用於根元素。

范例使用 withStyles() 将自定义样式注入 DOM,并通过其 classes 属性将类名传递给 ClassNames 组件。这里可以选择任何其他解决方案

import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import Button from '@material-ui/core/Button';
import { withStyles } from '@material-ui/core/styles';

const styles = {
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    borderRadius: 3,
    border: 0,
    color: 'white',
    height: 48,
    padding: '0 30px',
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
  },
};

function ClassNames(props) {
  const { classes, children, className, ...other } = props;

  return (
    <Button className={clsx(classes.root, className)} {...other}>
      {children || 'class names'}
    </Button>
  );
}

ClassNames.propTypes = {
  children: PropTypes.node,
  classes: PropTypes.object.isRequired,
  className: PropTypes.string,
};

export default withStyles(styles)(ClassNames);

关於Clsx,他可以减少我们用三元运算的方式撰写 className。
本来的写法:

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

引入之後:

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

用 classes 覆盖样式

当 className 属性不够用时,并且需要访问更深层次的元素,可以利用 classes 对象属性来自定义 Material-UI 为给定组件注入的所有 CSS。

每个组件的classes列表记录在组件 API 页面中,可以透过浏览官方文件的 component API 或者直接透过 dev tools 查看,这个例子也使用了 withStyles()(如上文),但在这里,ClassesNesting 使用 Button 的 classes 属性来提供一个对象,该对象将要覆盖的 classes 名称(样式规则)映射到要应用的 CSS class names(值)。组件的现有classes将继续注入,因此只需提供想要添加或覆盖的特定样式。
请注意,除了按钮样式之外,按钮标签的大小写也已更改:

const useStyles = makeStyles({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    borderRadius: 3,
    border: 0,
    color: 'white',
    height: 48,
    padding: '0 30px',
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
  },
  label: {
    textTransform: 'capitalize',
  },
});
// ...in export function
const classes = useStyles();
// ...in return
<Button
  classes={{
    root: classes.root, // class name, e.g. `classes-nesting-root-x`
    label: classes.label, // class name, e.g. `classes-nesting-label-x`
  }}
>
  classes nesting
</Button>

使用global class name覆盖样式

参考连结

透过 dev tools

浏览器开发工具可以节省大量时间。
Material-UI 的class names 遵循模式:
Mui[component name]-[style rule name]-[UUID]
使用开发工具,你知道你需要定位 Button 组件和标签样式规则

<Button classes={{ label: 'my-class-name' }} />

Shorthand

上面的范例可以通过使用与子组件相同的 CSS API 来压缩。在这个例子中,withStyles() HOC 正在注入一个由 Button 组件使用的 classes 属性。

const StyledButton = withStyles({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    borderRadius: 3,
    border: 0,
    color: 'white',
    height: 48,
    padding: '0 30px',
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
  },
  label: {
    textTransform: 'capitalize',
  },
})(Button);
// in retutn
<StyledButton>classes shorthand</StyledButton>

Pseudo-classes 伪类

组件的特殊状态,例如 hover, focus, disabled 或 selected,特异性是应用於给定 CSS 声明的权重。
为了覆盖组件的特殊状态,你需要增加特异性。

.Button {
  color: black;
}
.Button:disabled { /* Increase the specificity */
  color: white;
}
// in return
<Button disabled className="Button">

有时後不能使用伪类,因为平台中不存在状态。以MenuItem 组件和选中状态为例,除了访问嵌套元素外,classes 属性还可用於自定义 Material-UI 组件的特殊状态:

.MenuItem {
  color: black;
}
.MenuItem.selected { /* Increase the specificity */
  color: blue;
}
// in return
<MenuItem selected classes={{ root: 'MenuItem', selected: 'selected' }}>

使用 $ruleName 引用同一样式表中的规则

jss-nested 插件可以使增加特异性的过程更容易。

const styles = {
  root: {
    '&$disabled': {
      color: 'white',
    },
  },
  disabled: {},
};

需要将生成的两个类名(root 和 disabled)应用於 DOM 以使其工作。

// in return
<Button
  disabled
  classes={{
    root: classes.root, // class name, e.g. `root-x`
    disabled: classes.disabled, // class name, e.g. `disabled-x`
  }}
>
  classes state
</Button>

以上就是今天的全部内容了,明天会接续 2~5 的方法讲解。


<<:  新新新手阅读 Angular 文件 - pathMatch(3) - Day29

>>:  Day 14 - Functor

ETA Screen (3)

我们这次会为班次页加上自动更新和顺带为下一篇实作错误 banner 做准备。 我们这页除非显示不能连...

若市场总是有效率,我就是在街上乞讨的流浪汉。

若市场总是有效率,我就是在街上乞讨的流浪汉。 I'd be a bum on the street ...

[NestJS 带你飞!] DAY27 - Swagger (下)

API 操作设计 上一篇我们让 API 的参数能够顺利显示在 Swagger UI 中,在设计完参数...

【把玩Azure DevOps】Day10 CI/CD从这里:第2个Pipeline,建立共用的Build Pipeline

从前面的几篇文章应该已经知道建立新的Pipeline可以从哪里开始,所以废话不多说,第二个Pipel...

Day11 HTML一

如果有一些编写网页的基础,在之後撰写爬虫程序时会比较轻松呦~ 接下来的几天,会简单地介绍HTML与C...