react material ui完整教程(jsx)

react | 2022-09-12 22:29:36

整个material ui的案例先整javascript的,此教程会包含react和mui的基础知识,后面有需要再搞搞typescript.

先贴一下文档

react官方中文文档:https://react.docschina.org/docs/getting-started.html

material ui官方文档:https://mui.com/zh/material-ui/getting-started/overview/

react 路由:https://react-router.docschina.org/

 

0.基础总结

虚拟dom:通过虚拟dom和真实dom的对比,减少渲染的内容,稍微注意key的使用

jsx:组件都写在jsx里面,普通js写在js文件里面,甚至css in js,彻底js化了,这也是和vue最大的区别

组件:一切皆组件,css,图片,文件都是组件,官方推荐用函数式组件

hook:官方推荐用函数式组件,那就必须使用钩子函数,useState,useEffect等钩子

路由:这个都查不多

redux:有必要吧,像vue的store

组件通信:props,状态提升,context,pubsub等

 

1.material ui是什么

material ui是半官方的react ui组件库,比antd使用的人更多,但是国内使用antd的人多。

Material UI 是一个开源的 React 组件库,它实现了 Google 的Material Design。

2.搭建react框架

npm install create-react-app yarn -g
create-react-app stack-mui
cd stack-mui
yarn start

会自动弹出浏览器访问http://localhost:3000/

3.安装mui

#安装mui和样式库
yarn add @mui/material @emotion/react @emotion/styled
#安装字体
yarn add @fontsource/roboto
#安装图标
yarn add @mui/icons-material

yarn add @mui/lab

 

安装redux

yarn add redux

yarn add react-redux

yarn add @reduxjs/toolkit

 

 

4.创建material ui基础组件

先创建一些基础页面组件用来测试,后面再慢慢完善这些基础组件,先全部显示出来

4.1创建主界面viewport

import React from 'react';
import Box from '@mui/material/Box';

import Navigation from '../navigation';
import MainTabs from '../mainTabs';


export default function Viewport() {

    const [activeMenu, setActiveMenu] = React.useState({});

    const transActiveMenu=(menu)=>{
        setActiveMenu(menu);
    }

    return (
        <Box sx={{display: 'flex', width: '100vw', height: '100vh'}}>
            <Navigation transActiveMenu={transActiveMenu} style={{width: '250px', border: 'solid 1px #ddd'}}></Navigation>
            <MainTabs activeMenu={activeMenu} style={{width: 'calc(100vw - 250px)'}}></MainTabs>
        </Box>
    );
}

然后在app中引用


import {BrowserRouter} from 'react-router-dom'

import logo from './logo.svg';
import './App.css';

import Viewport from './views/viewport';

import {menuSlice} from "./redux/store"



function App() {
  return (
    <BrowserRouter>
      <Viewport></Viewport>
    </BrowserRouter>
  );
}

export default App;

4.2导航菜单

import React from 'react';
import MenuItem from "./MenuItem";
import List from '@mui/material/List';

import StarBorder from '@mui/icons-material/StarBorder';
import AppBar from '@mui/material/AppBar';
import Typography from '@mui/material/Typography';
import MenuIcon from '@mui/icons-material/Menu';
import IconButton from '@mui/material/IconButton';
import Toolbar from '@mui/material/Toolbar';
import AdbIcon from '@mui/icons-material/Adb';
import Box from '@mui/material/Box';


export default function Navigation(props) {
    const {style,transActiveMenu}=props;

    const menuData = [{
        id: 1, title: "主页", icon: "MoveToInbox", url: "/"
    }, {
        id: 2, title: "系统管理", icon: "Drafts",
        child: [{
            id: 21, title: "用户管理", icon: "Send", url: "/system/user"
        }, {
            id: 22, title: "菜单管理", icon: "ExpandLess", url: "/system/menu"
        }]
    }, {
        id: 3, title: "系统工具", icon: "ExpandMore",
        child: [{
            id: 31, title: "系统监控", icon: "StarBorder", url: "/tools/monitor",
            child: [{
                id: 131, title: "日志监控", icon: "Airplay", url: "/tools/monitor/LogMonitor"
            }]
        }]
    }]


    const [menuCollapse, setMenuCollapse] = React.useState({});
    const [activeMenu, setActiveMenu] = React.useState(0);

    const handlerClick = (menu) => {
        menuCollapse[menu.id] = !menuCollapse[menu.id];
        setMenuCollapse({...menuCollapse});
        setActiveMenu(menu);
        transActiveMenu(menu);
    }

    return (
        <List sx={style}
            component="nav"
            aria-labelledby="nested-list-subheader"
            subheader={
                <Box>
                    <AppBar position="static">
                        <Toolbar variant="dense">
                            <AdbIcon sx={{display: {xs: 'none', md: 'flex'}, mr: 1}}/>
                            <Typography color="inherit" component="div" sx={{flexGrow: 1}}>
                                MUI案例系统
                            </Typography>
                            <div>
                                <IconButton edge="end" color="inherit" aria-label="menu">
                                    <MenuIcon/>
                                </IconButton>

                            </div>
                        </Toolbar>
                    </AppBar>


                </Box>
            }
        >

            <MenuItem items={menuData} menuCollapse={menuCollapse} activeMenu={activeMenu} handlerClick={handlerClick}></MenuItem>

        </List>
    );
}
import React from 'react';
import {IconsMap} from "../../components/iconList";
import {ExpandMore,ExpandLess} from '@mui/icons-material';
import {Collapse,List,ListItemButton,ListItemText,ListItemIcon} from '@mui/material';
import {NavLink} from "react-router-dom";

function createMenuList(menuItems,menuCollapse,activeMenu,handlerClick,level){
    return menuItems.map(currentMenu => {
        const {id,title,icon,child,url} = currentMenu;
        const toUrl=url?url:"/";
        const IconTag=IconsMap[icon];
        const hasChild=child && child.length>0;

        const childMenus=hasChild?createMenuList(child,menuCollapse,activeMenu,handlerClick,level+1):null;

        const listItem=(
            <ListItemButton selected={id===activeMenu.id} sx={{pl: level*2}} onClick={() => handlerClick(currentMenu)}>
                <ListItemIcon >
                    <IconTag></IconTag>
                </ListItemIcon>
                <ListItemText primary={title}/>
                {hasChild?(menuCollapse[id]? <ExpandLess/> : <ExpandMore/>):<React.Fragment/>}
            </ListItemButton>
        )

        return (
            <React.Fragment key={id}>
                {hasChild?listItem:
                    <NavLink style={{textDecoration: 'none', color: 'inherit'}} to={toUrl} >
                        {listItem}
                    </NavLink>
                }

                {hasChild &&
                <Collapse in={menuCollapse[id]}>
                    <List component="div" disablePadding>
                        {[...childMenus]}
                    </List>
                </Collapse>
                }
            </React.Fragment>
        );
    })
}



{/*<MenuList/>*/}
{/*<ListItemButton>*/}
{/*    <ListItemIcon>*/}
{/*        <SendIcon/>*/}
{/*    </ListItemIcon>*/}
{/*    <ListItemText primary="主页"/>*/}
{/*</ListItemButton>*/}

{/*<ListItemButton onClick={() => handlerCollapse("xtgl")}>*/}
{/*    <ListItemIcon>*/}
{/*        <StarBorder/>*/}
{/*    </ListItemIcon>*/}
{/*    <ListItemText primary="系统管理"/>*/}
{/*    {menuCollapse["xtgl"] ? <ExpandLess/> : <ExpandMore/>}*/}
{/*</ListItemButton>*/}
{/*<Collapse in={menuCollapse["xtgl"]} timeout="auto" unmountOnExit>*/}
{/*    <List component="div" disablePadding>*/}
{/*        <NavLink style={{textDecoration: 'none', color: 'inherit'}} to="/system/user">*/}
{/*            <ListItemButton sx={{pl: 4}} selected>*/}
{/*                <ListItemIcon>*/}
{/*                    <AccountBoxIcon/>*/}
{/*                </ListItemIcon>*/}

{/*                <ListItemText primary="用户管理"></ListItemText>*/}

{/*            </ListItemButton>*/}
{/*        </NavLink>*/}
{/*        <ListItemButton sx={{pl: 4}}>*/}
{/*            <ListItemIcon>*/}
{/*                <ReorderIcon/>*/}
{/*            </ListItemIcon>*/}
{/*            <ListItemText primary="菜单管理"/>*/}
{/*        </ListItemButton>*/}
{/*    </List>*/}
{/*</Collapse>*/}
{/*<ListItemButton onClick={() => handlerCollapse("xtgj")}>*/}
{/*    <ListItemIcon>*/}
{/*        <AirplayIcon/>*/}
{/*    </ListItemIcon>*/}
{/*    <ListItemText primary="系统工具"/>*/}
{/*    {menuCollapse["xtgj"] ? <ExpandLess/> : <ExpandMore/>}*/}
{/*</ListItemButton>*/}
{/*<Collapse in={menuCollapse["xtgj"]} timeout="auto" unmountOnExit>*/}
{/*    <List component="div" disablePadding>*/}
{/*        <ListItemButton sx={{pl: 4}}>*/}
{/*            <ListItemIcon>*/}
{/*                <AdbIcon/>*/}
{/*            </ListItemIcon>*/}
{/*            <ListItemText primary="系统监控"/>*/}
{/*        </ListItemButton>*/}

{/*        <Collapse in={menuCollapse["xtgj"]} timeout="auto" unmountOnExit>*/}
{/*            <List component="div" disablePadding>*/}
{/*                <ListItemButton sx={{pl: 8}}>*/}
{/*                    <ListItemIcon>*/}
{/*                        <AdbIcon/>*/}
{/*                    </ListItemIcon>*/}
{/*                    <ListItemText primary="系统监控"/>*/}
{/*                </ListItemButton>*/}
{/*            </List>*/}
{/*        </Collapse>*/}

{/*        <ListItemButton sx={{pl: 4}}>*/}
{/*            <ListItemIcon>*/}
{/*                <AdbIcon/>*/}
{/*            </ListItemIcon>*/}
{/*            <ListItemText primary="系统监控"/>*/}
{/*        </ListItemButton>*/}
{/*    </List>*/}
{/*</Collapse>*/}


export default function MenuItem(props){
    return createMenuList(props.items,props.menuCollapse,props.activeMenu,props.handlerClick,0);
}

 

 

4.3 maitabs

import React from "react";
import {Box,Tabs,Tab} from '@mui/material';
import TabContext from '@mui/lab/TabContext';
import TabPanel from '@mui/lab/TabPanel';
import Typography from '@mui/material/Typography';

import Dashboard from '../dashboard';
import Menu from '../system/menu';
import User from '../system/user';
import SystemMonitor from '../tools/systemMonitor';

import {Routes, Route} from 'react-router-dom'
import { useLocation } from "react-router";




import Close from '@mui/icons-material/Close';

import Send from '@mui/icons-material/Send';

export default function MainTabs(props) {
    //props
    const {style,activeMenu} = props;


    //state
    const [tabsValue, setTabsValue] = React.useState("1");
    const [tabsList, setTabsList] = React.useState([
        {title:"主页",id:1,url:"/",closeAble:false}
    ]);

    const handleChange = (event, newValue) => {
        setTabsValue(`${newValue}`);
    };


    //event
    const location = useLocation();
    React.useEffect(() => {
        const url=location.pathname;
        addTabByMenu(url);
    }, [location]);

    //function
    const addTabByMenu=(url)=>{
        if(activeMenu&&activeMenu.url===url){
            const isExitTab=tabsList.some(tab=>tab.id===activeMenu.id)
            const newTablsValue=`${activeMenu.id}`;
            if(isExitTab){
                if(tabsValue!==newTablsValue){
                    setTabsValue(newTablsValue);
                }
            }else{
                tabsList.push({...activeMenu,closeAble:true})
                setTabsList([...tabsList]);
                setTabsValue(newTablsValue);
            }
        }
    }

    //todo 出问题了 菜单信息必须放全局,组件路由,否则路由刷新的时候找不到tab的名称

    const closeTab = (tabId)=>{
        tabsList.some((item,i)=>{
            if(item.id===tabId){
                tabsList.splice(i,1);
                // setTabsValue(newTablsValue);
                // setTabsList([...tabsList]);
            }
        })
    }



    return (
        <Box sx={style}>
            <TabContext value={tabsValue}>
                <Box sx={{borderBottom: 1, borderColor: 'divider'}}>
                    <Tabs
                        value={tabsValue}
                        onChange={handleChange}
                        variant="scrollable"
                        scrollButtons="auto"
                    >
                        {/*<Tab label="主页" style={{minHeight:'48px'}} value="0" iconPosition="end" icon={<Close onClick={()=>{alert(1)}} fontSize="small"/>} />*/}
                        {
                            tabsList.map(oneTab=>{
                                return (<Tab key={oneTab.id} label={oneTab.title}  value={`${oneTab.id}`} icon={oneTab.closeAble?<Close onClick={()=>{closeTab(oneTab.id)}} fontSize="small"/>:<React.Fragment />} style={{minHeight:'48px'}}  iconPosition="end" />)
                            })
                        }


                    </Tabs>
                </Box>
                <TabPanel value="0"><Dashboard /></TabPanel>
            </TabContext>
        </Box>
    );
}
 

看一下效果

代码结构

接下来我要使用路由,实现点击菜单,在tabs上添加对应的界面

 

5.react 路由

5.1安装路由组件

yarn add react-router-dom

4.2创建路由表

在src路径下面创建routes文件夹,然后下面创建index.jsx

import { useRoutes } from 'react-router-dom';

import Viewport from './views/Viewport';
import Dashboard from '../Dashboard';
import Menu from '../system/Menu';
import User from '../system/User';
import SystemMonitor from '../tools/SystemMonitor';

export default function Routes() {
    return useRoutes([{
        path: '/',
        element: <Viewport />,
        children: [{
            path: 'dashboard',
            element: <Dashboard />
        },{
            path: 'system',
            children: [{
                path: 'user',
                element: <User />
            },{
                path: 'menu',
                element: <Menu />
            }]
        },{
            path: 'tools',
            children: [{
                path: 'systemMonitor',
                element: <SystemMonitor />
            }]
        }]
    }]);
}

 

 

 

 

登录后即可回复 登录 | 注册
    
关注编程学问公众号