React 综合案例

React 05. 综合案例

1、 项目初始化

创建项目

$ npx create-react-app app01

项目降级:

$ npm i react@17 react-dom@17 axios react-router-dom@5 antd --force -S

编辑src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <App/>,
  document.querySelector("#root")
)

完善项目结构

app01/
	node_modules/
	public/
	src/
		|-- App.js
		|-- App.css
		|-- index.js
		|-- index.css
	package.json
	package-lock.json
	.gitignore

2、公共模块-路由

创建路由组件和路由映射规则

  • src/router/index.js:路由映射规则
  • src/router/RouterView.jsx:路由组件

src/router/index.js

/** 路由映射规则 */

const routes = [
  // {
  //   name: 'home',
  //   path: '/home',
  //   component: Home
  // }
]

export default routes

② 添加路由组件src/router/RouterView.jsx

/** 路由组件 */
import React, {Suspense} from 'react'

import {
  Switch,
  Route,
  Redirect
} from 'router-react-dom'

export default function RouterView(props) {
  const { routes } = props
  return (<Suspense fallback="加载中...">
    <Switch>
      {
        routes.map(route => {
          if(route.redirect) {
            return <Route key={route.name}
                          path={route.path}
                          exact={route.exact}>
                      <Redirect to={route.redirect}/>
                    </Route>
          } else {
            return <Route key={route.name}
                          path={route.path}
                          render={props => {
                            return <route.component {...props} 
                                     children={route.children}/>
                          }}
          }
        })
      }
    </Switch>
  </Suspense>)
}

③ 实现路由页面跳转

  • 一级路由:注册、登录、布局
  • 二级路由(布局):主页、商品管理、品牌管理、关于我们

完善组件

src/
	views/
		Reg/
			index.jsx
			Reg.css
		Login/
			index.jsx
			Login.css
		Main/
			index.jsx
			Main.css
		Home/
			index.jsx
			Home.css
		Goods/
			index.jsx
			Goods.css
		Brand/
			index.jsx
			Brand.css
		About/
			index.jsx
			About.css

一级路由:编辑src/App.js

import './App.css';

import {
  BrowserRouter as Router,
  NavLink
} from 'react-router-dom'

import routes from './router';
import RouterView from './router/RouterView';

function App() {
  return (
    <div className="App">
      <h2>入口模块</h2>
      <Router>
        <nav>
          <NavLink to="/main">LOGO</NavLink>
          <div>
            <NavLink to="/login">登录</NavLink>
            <NavLink to="/reg">注册</NavLink>
          </div>
        </nav>

        <hr />
        <RouterView routes={routes} />
      </Router>
    </div>
  );
}

export default App;

二级路由:src/views/Main.jsx

import React, { Component } from 'react'

import {  
  NavLink
} from 'react-router-dom';
import RouterView from '../../router/RouterView'

export default class Main extends Component {
  render() {
    return (
      <div>
        <RouterView routes={this.props.children}/>
        <hr/>
        <ul>
          <li><NavLink to="/main/home">首页</NavLink></li>
          <li><NavLink to="/main/goods">商品</NavLink></li>
          <li><NavLink to="/main/brand">品牌</NavLink></li>
          <li><NavLink to="/main/about">关于我们</NavLink></li>
        </ul>
      </div>
    )
  }
}

3、视图组件库

(1) 初始化

确认安装视图库

$ npm i antd --force -S

安装craco

$ npm i @craco/craco --force -S

安装less解析模块

$ npm i craco-less --force -S

创建配置文件:craco.config.js

const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

修改package.json,修改启动命令:

{
  "name": "app01",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@craco/craco": "^6.4.5",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "antd": "^4.21.5",
    "axios": "^0.27.2",
    "craco-less": "^2.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.3.3",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "craco start",					// 修改启动命令
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

修改App.css,修改为App.less,编辑内容

@import '~antd/dist/antd.less';

修改App.js,将css引入部分修改

// import './App.css';
import './App.less'
...
(2) 布局页面

编辑src/views/Main/index.jsx,添加基础网页布局

import { Layout, Menu } from 'antd';
import React, { Component } from 'react';
import './Main.less'
import RouterView from '../../router/RouterView';

const { Header, Footer, Sider, Content } = Layout;

function getItem(label, key, icon, children, type) {
  return {
    key,
    icon,
    children,
    label,
    type,
  };
}

const items = [
  getItem('首页', '/main/home'),
  getItem('系统管理', 'sub1', '', [
    getItem('菜单管理', '/main/menus'),
    getItem('角色管理', '/main/roles'),
    getItem('商品管理', '/main/users'),
  ]),
  getItem('业务管理', 'sub2', '', [
    getItem('商品管理', '/main/goods'),
    getItem('品牌管理', '/main/brand'),
    getItem('关于我们', '/main/about'),
  ])
];

export default class Main extends Component {

  changeMenu({ item, key, keyPath, domEvent }) {
    console.log(item, key, keyPath, domEvent, "用户点击了菜单")
    // 编程式导航实现页面跳转
    this.props.history.push(key)
  }

  componentDidMount() {
    console.log(this.props.location)
  }

  render() {
    return (
      <Layout>
        <Sider>
          <h2 className="logo">LOGO</h2>
          <Menu
            defaultSelectedKeys={this.props.location.pathname}
            defaultOpenKeys={['sub1']}
            mode="inline"
            theme="dark"
            items={items}
            onClick={this.changeMenu.bind(this)}
          />
        </Sider>
        <Layout>
          <Header>
            {this.props.location.pathname}
          </Header>
          <Content>
            <RouterView routes={this.props.children}></RouterView>
          </Content>
          <Footer>Footer</Footer>
        </Layout>
      </Layout>
    )
  }
}

4、页面数据

(1)封装请求模块

编辑:src/plugins/http.js

/** axios封装 */
import { Component } from 'react'
import axios from 'axios'

const instance = axios.create({
  baseURL: 'http://localhost:3000'
})

instance.interceptors.request.use(requset => {
  return requset
})

instance.interceptors.response.use(response => {
  return response.data
})

Component.prototype.$http = instance

export default instance

入口模块index.js,引入当代码生效

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import './plugins/http'			// 引入模块

ReactDOM.render(
  <App/>,
  document.querySelector("#root")
)

(2) 请求数据

编辑品牌管理页面:src/views/Brand.jsx

import React, { Component } from 'react'

import { Table, Space, Button,Card } from 'antd';

export default class Brand extends Component {

  state = {
    brandList: []
  }

  columns = [
    {
      title: "序号",
      dataIndex: "id",
      key: "id"
    },
    {
      title: "名称",
      dataIndex: "bname",
      key: "bname"
    },
    {
      title: "单价",
      dataIndex: "bprice",
      key: "bprice"
    },
    {
      title: "操作",
      render: () => (
        <Space>
          <Button type="primary">编辑</Button>
          <Button type="danger">删除</Button>
        </Space>
      )
    }
  ]

  componentDidMount() {
    this.getBrand()
  }

  getBrand() {
    this.$http.get('/brand/list').then(response => {
      if(response.code === 200) {
        console.log('response',response)
        this.setState({
          brandList: response.data
        })
      }
    })
  }

  render() {
    return (
      <>
        <h2>品牌管理</h2>
        <Table dataSource={this.state.brandList} 
              rowKey="id"
              columns={this.columns}/>
      </>
    )
  }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值