最近工作中须要开发手机端H5页面,没有应用相熟的 React + Antd-mobile, React + Taro UI,Vue + uView ,而是应用了 React + Material-UI做了一次全新的尝试。而且正好最近React-router/React-router-dom 强行用 hooks模式 迭代了一个大版本@6;
目标: 看腻了antd的中台款式,体验一下Material的【暗黑模式】以及可配置的【调色板】。
React 相干版本信息:
"react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.6", "react-router": "^6.0.2", "react-router-dom": "^6.0.2",
Material-UI 相干版本信息:
"@emotion/react": "^11.6.0", "@emotion/styled": "^11.6.0", "@material-ui/core": "^5.0.0-beta.5", "@material-ui/styles": "^4.11.4", "@mui/icons-material": "^5.1.1", "@mui/lab": "^5.0.0-alpha.56", "@mui/material": "^5.1.1",
应用组件有:Typography Button Radio Select Switch TextField Badge List Table Tooltip Alert Dialog Progress Accordion Card Paper Menu Pagination Grid Modal Date Range Picker...
遇到的问题:
1、须要定义 首选主题primary、次级主题secondary等色彩搭配配置
2、组件没有汉化,须要本人汉化【例如:日历等】
3、组件须要进行二次封装,使其更合乎国人审美
接入 Material-UI
Material-UI官网留神:组件倡议单组件引入,示例:
import { Button, Tabs, Modal, Box} from '@material-ui/core/index'; 与 import Button from '@material-ui/core/Button'; 区别 下面的引入形式,打包后的包体积是上面的包10倍左右...
主题的配置
在Color 色彩 中简略选取了几个色彩搭配为正文:primary的 dark为800色值、main为600色值、light为400色值; secondary的 dark为700色值、main为500色值、light为200色值;看集体审美,能够应用不同色调进行搭配。
themeConfig.js 文件const theme = { pink: { palette: { primary: { light: '#ec407a', main: '#d81b60', dark: '#ad1457', contrastText: '#000', }, secondary: { light: '#f48fb1', main: '#e91e63', dark: '#c2185b', contrastText: '#000', }, }, }, purple: { palette: { primary: { light: '#ab47bc', main: '#8e24aa', dark: '#6a1b9a', }, secondary: { light: '#ce93d8', main: '#9c27b0', dark: '#7b1fa2', }, }, }, deepPurple: { palette: { primary: { light: '#7e57c2', main: '#5e35b1', dark: '#4527a0', contrastText: '#000', }, secondary: { light: '#b39ddb', main: '#673ab7', dark: '#512da8', contrastText: '#000', }, }, }, blue: { palette: { primary: { light: '#42a5f5', main: '#1e88e5', dark: '#1565c0', contrastText: '#000', }, secondary: { light: '#90caf9', main: '#2196f3', dark: '#1976d2', contrastText: '#000', }, }, }, teal: { palette: { primary: { light: '#26a69a', main: '#00897b', dark: '#00695c', contrastText: '#000', }, secondary: { light: '#80cbc4', main: '#009688', dark: '#00796b', contrastText: '#000', }, }, }, green: { palette: { primary: { light: '#66bb6a', main: '#43a047', dark: '#2e7d32', contrastText: '#000', }, secondary: { light: '#a5d6a7', main: '#4caf50', dark: '#388e3c', contrastText: '#000', }, }, }, amber: { palette: { primary: { light: '#ffca28', main: '#ffb300', dark: '#ff8f00', contrastText: '#000', }, secondary: { light: '#ffe082', main: '#ffc107', dark: '#ffa000', contrastText: '#000', }, }, }, blueGrey: { palette: { primary: { light: '#ECEFF1', main: '#90A4AE', dark: '#455A64', contrastText: '#000', }, secondary: { light: '#E0E0E0', main: '#757575', dark: '#424242', contrastText: '#000', }, }, }, cyan: { palette: { primary: { light: '#E0F7FA', main: '#00BCD4', dark: '#00838F', contrastText: '#000', }, secondary: { light: '#E1F5FE', main: '#039BE5', dark: '#01579B', contrastText: '#000', }, }, },};export default theme;
全局的根底CSS款式配置
import themePalette from './themePaletteMode';import { colorToRgba } from './../../utils/colorToRgba';const applicationTheme = (color, mode, direction) => ({ direction, palette: { type: mode, primary: themePalette(color, mode).palette.primary, secondary: themePalette(color, mode).palette.secondary, action: { hover: mode === 'dark' ? 'rgba(80,80,80, 0.9)' : 'rgba(80,80,80, 0.05)', hoverOpacity: 0.05, }, }, typography: { useNextVariants: true, fontFamily: ['Open Sans', 'sans-serif'].join(','), title: { fontWeight: 600, }, body2: { fontWeight: 500, }, fontWeightMedium: 600, }, shade: { light: '0 10px 15px -5px rgba(62, 57, 107, .07)', }, glow: { light: `0 2px 20px -5px ${themePalette(color, mode).palette.primary.main}`, medium: `0 2px 40px -5px ${themePalette(color, mode).palette.primary.main}`, dark: `0 2px 40px 0px ${themePalette(color, mode).palette.primary.main}`, }, rounded: { small: '8px', medium: '12px', big: '20px', }, shadows: mode === 'dark' ? [ 'none', `0px 1px 3px 0px rgba(100,100,100, 0.6),0px 1px 1px 0px rgba(100,100,100, 0.4),0px 2px 1px -1px rgba(100,100,100, 0.2)`, '0px 1px 5px 0px rgba(100,100,100, 0.6),0px 2px 2px 0px rgba(100,100,100, 0.4),0px 3px 1px -2px rgba(100,100,100, 0.2)', '0px 1px 8px 0px rgba(100,100,100, 0.6),0px 3px 4px 0px rgba(100,100,100, 0.4),0px 3px 3px -2px rgba(100,100,100, 0.2)', '0px 2px 4px -1px rgba(100,100,100, 0.6),0px 4px 5px 0px rgba(100,100,100, 0.4),0px 1px 10px 0px rgba(100,100,100, 0.2)', '0px 3px 5px -1px rgba(100,100,100, 0.6),0px 5px 8px 0px rgba(100,100,100, 0.4),0px 1px 14px 0px rgba(100,100,100, 0.2)', '0px 3px 5px -1px rgba(100,100,100, 0.6),0px 6px 10px 0px rgba(100,100,100, 0.4),0px 1px 18px 0px rgba(100,100,100, 0.2)', '0px 4px 5px -2px rgba(100,100,100, 0.6),0px 7px 10px 1px rgba(100,100,100, 0.4),0px 2px 16px 1px rgba(100,100,100, 0.2)', '0px 5px 5px -3px rgba(100,100,100, 0.6),0px 8px 10px 1px rgba(100,100,100, 0.4),0px 3px 14px 2px rgba(100,100,100, 0.2)', '0px 5px 6px -3px rgba(100,100,100, 0.6),0px 9px 12px 1px rgba(100,100,100, 0.4),0px 3px 16px 2px rgba(100,100,100, 0.2)', '0px 6px 6px -3px rgba(100,100,100, 0.6),0px 10px 14px 1px rgba(100,100,100, 0.4),0px 4px 18px 3px rgba(100,100,100, 0.2)', '0px 6px 7px -4px rgba(100,100,100, 0.6),0px 11px 15px 1px rgba(100,100,100, 0.4),0px 4px 20px 3px rgba(100,100,100, 0.2)', '0px 7px 8px -4px rgba(100,100,100, 0.6),0px 12px 17px 2px rgba(100,100,100, 0.4),0px 5px 22px 4px rgba(100,100,100, 0.2)', '0px 7px 8px -4px rgba(100,100,100, 0.6),0px 13px 19px 2px rgba(100,100,100, 0.4),0px 5px 24px 4px rgba(100,100,100, 0.2)', '0px 7px 9px -4px rgba(100,100,100, 0.6),0px 14px 21px 2px rgba(100,100,100, 0.4),0px 5px 26px 4px rgba(100,100,100, 0.2)', '0px 8px 9px -5px rgba(100,100,100, 0.6),0px 15px 22px 2px rgba(100,100,100, 0.4),0px 6px 28px 5px rgba(100,100,100, 0.2)', '0px 8px 10px -5px rgba(100,100,100, 0.6),0px 16px 24px 2px rgba(100,100,100, 0.4),0px 6px 30px 5px rgba(100,100,100, 0.2)', '0px 8px 11px -5px rgba(100,100,100, 0.6),0px 17px 26px 2px rgba(100,100,100, 0.4),0px 6px 32px 5px rgba(100,100,100, 0.2)', '0px 9px 11px -5px rgba(100,100,100, 0.6),0px 18px 28px 2px rgba(100,100,100, 0.4),0px 7px 34px 6px rgba(100,100,100, 0.2)', '0px 9px 12px -6px rgba(100,100,100, 0.6),0px 19px 29px 2px rgba(100,100,100, 0.4),0px 7px 36px 6px rgba(100,100,100, 0.2)', '0px 10px 13px -6px rgba(100,100,100, 0.6),0px 20px 31px 3px rgba(100,100,100, 0.4),0px 8px 38px 7px rgba(100,100,100, 0.2)', '0px 10px 13px -6px rgba(100,100,100, 0.6),0px 21px 33px 3px rgba(100,100,100, 0.4),0px 8px 40px 7px rgba(100,100,100, 0.2)', '0px 10px 14px -6px rgba(100,100,100, 0.6),0px 22px 35px 3px rgba(100,100,100, 0.4),0px 8px 42px 7px rgba(100,100,100, 0.2)', '0px 11px 14px -7px rgba(100,100,100, 0.6),0px 23px 36px 3px rgba(100,100,100, 0.4),0px 9px 44px 8px rgba(100,100,100, 0.2)', '0px 11px 15px -7px rgba(100,100,100, 0.6),0px 24px 38px 3px rgba(100,100,100 0.14),0px 9px 46px 8px rgba(100,100,100, 0.2)', ] : [ 'none', `0px 1px 3px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 1px 1px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 2px 1px -1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 1px 5px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 2px 2px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 3px 1px -2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 1px 8px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 3px 4px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 3px 3px -2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 2px 4px -1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 4px 5px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 1px 10px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 3px 5px -1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 5px 8px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 1px 14px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 3px 5px -1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 6px 10px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 1px 18px 0px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 4px 5px -2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 7px 10px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 2px 16px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 5px 5px -3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 8px 10px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 3px 14px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 5px 6px -3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 9px 12px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 3px 16px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 6px 6px -3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 10px 14px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 4px 18px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 6px 7px -4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 11px 15px 1px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 4px 20px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 7px 8px -4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 12px 17px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 5px 22px 4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 7px 8px -4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 13px 19px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 5px 24px 4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 7px 9px -4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 14px 21px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 5px 26px 4px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 8px 9px -5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 15px 22px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 6px 28px 5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 8px 10px -5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 16px 24px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 6px 30px 5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 8px 11px -5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 17px 26px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 6px 32px 5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 9px 11px -5px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 18px 28px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 7px 34px 6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 9px 12px -6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 19px 29px 2px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 7px 36px 6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 10px 13px -6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 20px 31px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 8px 38px 7px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 10px 13px -6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 21px 33px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 8px 40px 7px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 10px 14px -6px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 22px 35px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 8px 42px 7px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 11px 14px -7px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 23px 36px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 9px 44px 8px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, `0px 11px 15px -7px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.2, )},0px 24px 38px 3px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.14, )},0px 9px 46px 8px ${colorToRgba( themePalette(color, mode).palette.primary.light, 0.12, )}`, ], components: { MuiButton: { contained: { boxShadow: 'none', }, root: { borderRadius: 20, fontWeight: 600, }, sizeSmall: { padding: '7px 12px', }, }, },});export default applicationTheme;
正文:shadows 内容较长
残缺api配置项请参考官网
配置 theme白天/夜晚模式
import { useTheme } from '@mui/material/styles'; const theme = useTheme(); const { children } = props; ... <Box sx={{ minHeight: '100vh', bgcolor: theme.palette.mode === 'dark' ? '#000' : '#fff', color: theme.palette.mode === 'dark' ? '#fff' : '#000', }}> {children} </Box>
正文:theme 配置api中蕴含 background的配置项,能够应用自定义配置
配置调色板
在applicationTheme函数中曾经合并了themePalette(color, mode).palette,这里只须要在themePalette 函数中 进行自定义主题色就能够了,
import themeConfig from './themeConfig' const themePalette = (color, mode) => { return themeConfig[color]; }; export default themePalette;
正文:themeConfig文件在下面曾经粘贴进去了,这里我没有应用mode参数,能够依据我的项目理论状况 配置 dark/light不同的主题色。例如:pink下再细分 dark - palette / light - palette;
组件的汉化
以Date Range Picke 为示例:
原始 工夫区间选择器
汉化后:
官网中提供了一些api正文:其中有个留神点:1? 和 2? 两个部门找遍了api文档和 api源码都没有找到相干对应api,只能批改对应组件的源代码了,依据组件源代码 定位到
1? 的地位存在于 组件@mui/lab/CalendarPicker/PickersCalendarHeader.js 中 批改如下: transKey: month.getMonth() + 1, // 这里将 utils.format(month, 'month') 批改为 month.getMonth() + 1 children: month.getMonth() + 1 // 这里将 utils.format(month, 'month') 批改为 month.getMonth() + 1 2? 的地位存在于 组件@mui/lab/CalendarPicker/PickersCalendar.js中 批改如下: children: ['日','一','二','三','四','五','六'].map((day, i) => /*#__PURE__*/_jsx(PickersCalendarWeekDayLabel, { // 这里将 这里将 utils.getWeekdays() 批改为 ['日','一','二','三','四','五','六'] 应用 patch-package 将 批改后的打包成 patches包。
另外需注意:在设置inputFormat="yyyy/MM/dd" 后,控制台会弹出正告
The mask "__/__/____" you passed is not valid for the format used yyyy/MM/dd. Falling down to uncontrolled not-masked input.
这里 依据源代码查看 mask 相干配置项如下,暂无好的解决方案。
组件的二次封装
其中比拟罕用的有Input Select Modal等,上面做个简略介绍
1、Input组件 TextField InputBase
<Paper sx={{ p: '2px 4px', display: 'flex', alignItems: 'center', width: '100%' }}> <InputBase sx={{ ml: 1, flex: 1 }} placeholder="请输出" inputProps={{ 'aria-label': '请输出' }} onKeyUp={(e) => { ... }} /> <IconButton type="search" onClick={() => { ... }} sx={{ p: 1 }} aria-label="search"> <SearchIcon /> </IconButton> </Paper>
2、Select 组件 TextField
<TextField id="search_select" select sx={{ width: 130, bgcolor: 'transparent' }} value={currency} onChange={(e) => ...}> {selectArr.map((option) => ( <MenuItem className="search_item" key={option.value} value={option.value}> <span style={{ fontSize: 12 }}>{option.label}</span> </MenuItem> ))} </TextField>
正文:这里比拟留神的是款式的调整
#search_select { min-height: 30px !important; padding: 0 0 0 10px !important; line-height: 30px !important; } .search_item { min-height: 30px; line-height: 30px; padding: 0 0 0 10px; }
Modal组件
const style = { position: 'absolute', top: '50%', left: '50%', borderRadius: 2, transform: 'translate(-50%, -50%)', width: '60vw', bgcolor: 'background.paper', pt: 2, pb: 2, }; <Modal open={open} onClose={handleClose} hideBackdrop aria-labelledby="modal-modal-title" aria-describedby="modal-modal-description"> <Box sx={style}> <Typography sx={{ fontSize: 16, mb: 2, pl: 2, pb: 0.5 }} variant="h6" gutterBottom component="div"> {title} </Typography> <Box sx={{ display: 'flex', alignItem: 'center', justifyContent: 'center', flexWrap: 'wrap', }}> ... </Box> </Box> </Modal>
总结
Material-UI 可玩性还是比拟大的,官网也有很多的demo,然而因为版本升级到5.X后,很多api被废除了,搭配上须要本人去钻研了,总体上来说Material格调还是不错的。在后续的过程中再边总结,边更新文档吧。。。