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}/>
</>
)
}
}