编程知识 cdmana.com

Talking about the style scheme of react material UI

Google stay 2014 It was proposed that material design Design concept of , Very subversive , It's very popular abroad .

All kinds of front-end frameworks have emerged material design Style component library , among React The most popular material design Style component library is not  material-ui  Perhaps judge of particulars, .

mui-org/material-ui

This open source library is currently harvesting 61415 star

ec4c67f75d9a0560dedf713d8b5134cd.jpeg


npm The number of weekly downloads reached 139 ten thousand

The data is there , I don't need to go on “ Touted ” material-ui 了 .

This article is mainly to take you to appreciate  material-ui A new style scheme .


@material-ui/styles

material-ui Publish your own style scheme as a npm package , It's called @material-ui/styles (@material-ui/styles


CSS-in-JS

material-ui The style scheme embraces  CSS-in-JS , According to their documents , They also tried to use it LESS And so on , But the findings have obvious limitations , Finally, I hugged CSS-in-JS —— Unlocked   Topic nesting 、 Dynamic style 、 Self support   Other characteristics

( About css-in-js and other css Scheme comparison , This article will not discuss , Interested readers can search for )


Official documents claim that material-ui The style scheme has the following advantages



How to use

material-ui The style scheme supports three forms of API, But the underlying code and logic are consistent .

Code demonstration

  1. Hook API
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({ // css  object 
  root: {
    background'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border0,
    borderRadius3,
    boxShadow'0 3px 5px 2px rgba(255, 105, 135, .3)',
    color'white',
    height48,
    padding'0 30px',
  },
});

export default function Hook({
  const classes = useStyles(); // classes  object 
  return <Button className={classes.root}>Hook</Button>;
}

adopt makeStyles API , Pass in a description CSS The object of ( Hereinafter referred to as  css object ), You can get a custom Hook, Usually named useStyles ( Reference resources React In the official documents Customize hook The naming convention of

Call this in a functional component Hook, Get an object , Usually named  classes ( Notice the plural , Readers can think about the reason why it is plural )

Last , take  classes  Object's “ Corresponding value ” Assign to Component's className attribute , You have successfully customized the style of this component .

details :classes Object's root attribute The corresponding is css Object's root attribute


2. Styled components API

import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const MyButton = styled(Button)({
  background'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
  border0,
  borderRadius3,
  boxShadow'0 3px 5px 2px rgba(255, 105, 135, .3)',
  color'white',
  height48,
  padding'0 30px',
});

export default function StyledComponents({
  return <MyButton>Styled Components</MyButton>;
}

Use styled API You can use something like  styled-components  The grammar of , Of course, there is a difference —— styled-components It's using  es6 tagged template literals  and material-ui styled API The parameters of the return function are css object


3. Higher-order component API

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

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

function HigherOrderComponent(props{ 
  const { classes } = props;
  return <Button className={classes.root}>Higher-order component</Button>;
}

HigherOrderComponent.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(HigherOrderComponent);

Use withStyles API Receive one css Object returns a higher-order component function .

material-ui Of Higher-order component API Not only for function components, but also for class components , But in Hook After its popularity, this API Slowly out of the stage .


( The rest of this article only uses makeStyles API Do the following code demonstration )


Underlying principle

material-ui Aforementioned API At the bottom, there will be some “ Random html class name ” as well as Corresponding css The rules

With above makeStyles demo For example , Meeting Generate the following css The rule is inserted into html head

9674bf3578e9ff048bd262fa853f2cf5.jpeg

Custom style button Corresponding html The snippet is as follows

5299500e4ed0935bf509af2409b91f92.png



Summary

These three forms of API Can customize the style of components . In fact, you can find out by looking at the source code styled and withStyles It's called by the bottom layer  makeStyles API

https://github.com/mui-org/material-ui/blob/4b560848aa3b38b9cadc198c624abeb810aaf6a4/packages/material-ui-styles/src/withStyles/withStyles.js#L38

https://github.com/mui-org/material-ui/blob/4b560848aa3b38b9cadc198c624abeb810aaf6a4/packages/material-ui-styles/src/styled/styled.js#L52

The underlying principle is dynamic generation css The rule is inserted into html in .

These three API In the use of , The key points are two parts :

  1. css object
  2. Target component

Next, we will talk about css The composition and use of objects .



Nested selectors

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles({
  root: {
    color'red',
    '& p': {
      margin0,
      color'green',
      '& span': {
        color'blue',
      },
    },
  },
});

export default function NestedStylesHook({
  const classes = useStyles();

  return (
    <div className={classes.root}>
      This is red since it is inside the root.
      <p>
        This is green since it is inside the paragraph{' '}
        <span>and this is blue since it is inside the span</span>
      </p>
    </div>
  );
}

The above code can get the following effect

622637b648e15d9a1b8e6265623a8a61.png

Actually generated css The following rules


fcad7254b4dc95a14ba27a50da4732b7.png


Dynamically adjust according to the input value

Aforementioned css Objects are not necessarily simple objects .

You can pass a function to makeStyles (“ interpolation ”), In this way, the values of the generated styles can be changed according to the properties of the components . The rules that can be applied to this style of function , It can also be placed in CSS Attribute level

example 1:

const useStyles = makeStyles({
  //  Style rules 
  foo: props => ({
    backgroundColor: props.backgroundColor,
  }),
  bar: {
    // CSS  attribute 
    color: props => props.color,
  },
});

function MyComponent({
  //  Simulate component's props
  const props = { backgroundColor: 'black', color: 'white' };
  // Pass the props as the first argument of useStyles()
  const classes = useStyles(props);

  return <div className={`${classes.foo} ${classes.bar}`} />
}


example 2:

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

const useStyles = makeStyles({
  root: {
    background(props) =>
      props.color === 'red'
        ? 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'
        : 'linear-gradient(45deg, #2196F3 30%, #21CBF3 90%)',
    border0,
    borderRadius3,
    boxShadow(props) =>
      props.color === 'red'
        ? '0 3px 5px 2px rgba(255, 105, 135, .3)'
        : '0 3px 5px 2px rgba(33, 203, 243, .3)',
    color'white',
    height48,
    padding'0 30px',
    margin8,
  },
});

function MyButton(props{
  const { color, ...other } = props;
  const classes = useStyles(props);
  return <Button className={classes.root} {...other} />;
}

MyButton.propTypes = {
  color: PropTypes.oneOf(['blue', 'red']).isRequired,
};

export default function AdaptingHook() {
  return (
    <React.Fragment>
      <MyButton color="red">Red</MyButton>
      <MyButton color="blue">Blue</MyButton>
    </React.Fragment>
  );
}

design sketch :

cd25c330a69bc2c3de675e6ae390c8e6.png

The two buttons of the above code correspond to html Code

679785b715185df5d8c79b10a1452cb1.jpeg

Found that they shared a class name —— makeStyles-root-1, At the same time, each has a special class name makeStyles-root-2 and makeStyles-root-3

about makeStyles-root-1 We are not surprised at html head We found the corresponding css The rules

eb6c2aa45b5bba93adbaebae80a42486.png

But in html But you can't find makeStyles-root-2 and makeStyles-root-3

stay Chrome Developer tools see these two class The label of the style is constructed stylesheet

57c64e2125a91f6b497b1d0ea91560c0.png

constructed stylesheet  It's a kind of passing js Call special API structure css The technology of rules , Details can be found in the document

https://developers.google.com/web/updates/2019/02/constructable-stylesheets


Overlay style —— classes attribute

Next, change the angle , If you use material-ui Style schemes create some components ( Provides a default style ) And share it with other modules as a common component , How to make the callers customize the styles of these components ?

As mentioned above   Dynamically adjust according to the input value   It's a solution , But obviously it's a solution that allows only fine-tuning ; And the implementation of this scheme is usually cumbersome —— If you allow all styles to be adjusted , So all the styles are in css It's all functions .

Suppose the following is a component code we designed

//  A style inline table 
const useStyles = makeStyles({
  root: {}, //  A style rule 
  label: {}, //  A nested style rule 
});

function Nested(props{
  const classes = useStyles();
  return (
    <button className={classes.root}> // class  value  'makeStyles-root-1'
      <span className={classes.label}> // class  value  'makeStyles-label-2'
         Nested 
      </span>
    </button>
  );
}

function Parent({
  return <Nested />
}

So I am Parent How to customize this Nested Component's span What about the style ?

We can use  classes attribute   Overlay style

const useStyles = makeStyles({
  root: {}, //  A style rule 
  label: {}, //  A nested style rule 
});

function Nested(props{
  const classes = useStyles(props); //  Note the parameters here 
  return (
    <button className={classes.root}> // class  value  'makeStyles-root-1'
      <span className={classes.label}> // class  value  'makeStyles-label-2 my-label'
         Nested 
      </span>
    </button>
  );
}

function Parent({
  return <Nested classes={{ label: 'my-label' }} /> 
}

In the above code , We went to useStyles This hook In the middle of props As a parameter ( In fact, it's to make classes Pass in )

And in the Parent In the code of , We give Nested Pass in classes attribute ( The name is standard , Must abide by the

The final effect is generated by html in span Of class The value is ‘makeStyles-label-2 my-label’ —— Be careful my-label The order is at the end of , So its style will cover the front makeStyles-label-2 The style of .

above my-label Just to better illustrate , Here's a more practical example

const useStyles = makeStyles({
  root: {}, //  A style rule 
  label: {
    fontSize30,
    color'red'
  }, //  A nested style rule 
});

function Nested(props{
  const classes = useStyles(props); //  Note the parameters here 
  return (
    <button className={classes.root}>
      <span className={classes.label}> 
         Nested 
      </span>
    </button>
  );
}


const useStyles2 = makeStyles({
  mylabel: {
    color'green' //  Overlay style 
  }, 
});

function Parent({
  const classes = useStyles2();
  return <Nested classes={{ label: classes.mylabel }} /> 
}

The end result is

87f36294fa743733de36af3d624492d0.png

open Chrome Developer tools view styles

266213c0eafa628a162b980830952b6a.png



so The green font style covers the red font style , That is, the caller successfully overridden the default style



material-ui How does the component of allow users to customize styles

All of the above is true @material-ui/styles Design and use of , Next , Look at it together. @material-ui/core How the components in this component library allow users to customize styles

With Button For example , When we look at Button API When  Button API - Material-UI

You can see something like this

77bc84b08d51f63f55a7fdb914fbe898.jpeg

as well as

d956e1275776fb4ea5c55db1bef21b1b.jpeg

Follow the documentation tips , Let's try to customize when Button Of variant="text" And color="primary" Style of time

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

const useStyles = makeStyles({
  mybutton: {
    color'purple',
    fontSize30,
  },
});


export default function AdaptingHook({
  const classes = useStyles();
  return (
    <React.Fragment>
      <Button variant='text' color='primary' 
           classes={{textPrimary: classes.mybutton}}>Hi</Button>
    </React.Fragment>
  );
}

Be careful classses The property name of the object is textPrimary

The result is a The size of purple is 30 The button

949af1a595eae7f130031d80a9aaff25.png

Let's look at this button HTML Code

It's no surprise that makeStyles-mybutton-95 class value

however , When we Button Of color="primary" Change it to color="secondary" when , It turned into a Red normal size buttons ( Under the default theme secondary It's usually red )

53f75a72ce8e569f2b98ad4ca6b402f6.png

html It's also in the code Disappear 了 makeStyles-mybutton-95 class value

1f63452419091da6947a2e078783e934.png


How can this be done , View source code  https://github.com/mui-org/material-ui/blob/cdbaeefab373c13022cb4891ba878fe85b7d4154/packages/material-ui/src/Button/Button.js#L300

73b5f17ee5f66aebcdbaf09cca98fff9.jpeg

First of all, the source code uses clsx A generation class Name of the tool library ( You can see  lukeed/clsx )

clsx One of the uses of is , When the value of an attribute in an object is true when , This property name will be added with class Part of the value of .

namely : When variant by text, color by primary when , color !== 'default'&&color !== 'inherit' by true, therefore classes['textPrimary'] Will serve as a Final class Part of the value of , So the button shows Our custom purple 30 size

And when When variant by text, color by secondary when , color !== 'default'&&color !== 'inherit' by true, therefore classes['textSecondary'] Will serve as a Final class Part of the value of , But because of us Incoming classes No, textSecondary This attribute , So it doesn't work , Finally, the default red normal size style is displayed .




summary

The style scheme you use in your front-end project is still LESS, SASS Even css Do you ?

material-ui Style solutions Is it a shock or inspiration to you ? Feel free to leave a comment .

If the quality of the article is good , Please praise positively 、 like 、 Collect Sanlian !


p.s. material-ui There are other things in the style scheme , Such as the theme 、JSS Plug-ins, etc. , I feel it's less difficult , The documentation is easy to understand ,( Or too obscure , Rarely used ), This article will not introduce , If there is a strong demand from readers to write a part , I'll go on to add .



Reference link :

https://material-ui.com/zh/styles/basics/

styled-components

https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Button/Button.js


版权声明
本文为[osc_ sfm9hgdb]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224141846066r.html

Scroll to Top