背景
React是一个作为一个非常流行的前端框架,其生态圈及其繁荣,社区里有很多基于它的库。Ant Design
就是其中一个非常好用的ui库。
这是蚂蚁金服的一个ui库,里面封装了很多很好用的组件。
现在搭建的后台管理系统就是利用Ant Design
的组件来快速开发。
准备工作
首先最基本的肯定是要配置好React 开发所需要的环境。
这里,最快的方法是通过create-react-app
脚手架来快速构建项目了。
打开命令行,全局安装create-react-app
包
npm install create-react-app -g
然后进入要存放项目的目录,执行命令,新建我们的项目
create-react-app react_ant
最后,进入我们的项目,执行
npm start
浏览器就会自动打开,并跳转到http://localhost:3000/
,这就表明,我们的开发环境已经建好。可以随便更改app.js
中render
中的渲染内容来检验。
然后,我们的准备工作继续。
到现在,我们的开发环境是搭建起来了,但是我们的目标是是要搭建后台的管理系统,这其中,对用户数据的查改增删操作都要涉及到和后端的交互,我们总不能还要另外去租个服务器吧?其实,对于我们现在要处理的简单数据,完全没必要,那用什么能实现这些简单的需求来模拟我们线上的请求呢?json-server就能满足我们。
json-server可以为前端开发者快速搭建一个后端服务器。我们可以发送get
,post
, put
, delete
请求来修改服务器上预先设定好的假数据。
使用方法如下:
- 安装
npm install json-server -g
- 进入我们的
react-ant
项目,在项目根目录里面创建给文件夹叫做:server .在里面创建一个db.json。 在db.json先整一些数据,数据最外层得是一个对象,对象里的数组里的每条对象最好有id
进入server文件夹,执行命令,启动server
json-server 数据文件名 -w -p 端口号
这时候,我们就终端窗口就会提示我们的server启动信息
这时候我们直接访问localhost:2000/db
就能看到我们的数据。
- 然后在自己的项目里即可发起
get/post/put/delete
请求
服务器搭建好后,我们还要数据。
可以使用faker
快速生成前端开发需要的假数据。
中文版 faker-zh-cn
使用步骤:
安装
npm install faker-zh-cn --save--dev
- 进入server文件夹,新建
people.js
文件
根据需要的数据,结合npm上的api,编写people.js
var faker = require('faker-zh-cn');
function getData() {
var arr = [];
for (let i = 1; i <= 30; i++) {
arr.push({
id: i,
name: faker.Name.findName(),
email: faker.Internet.email(),
city: faker.Address.city()
})
}
return {peopleList: arr};
}
module.exports = getData;
然后正常打开json-server
,在浏览器打开对应网址,即能看到数据。
开始编码
项目结构
要做的这个后台管理系统很简单,只包含三个页面,列表页,编辑页,添加用户数据,同时还包含一个每个页面都会有的侧边栏,点击侧边栏可以切换列表页和添加用户数据页。列表页的每条数据都要设置删除和编辑用户数据的方法,并且每次操作数据都提供对用户体验良好的提示等。
项目的目录如下:
- public 存放的是公共的东西,包括Logo,单页面的html文件。
- server 存放后端数据的文件
- src 存放各个页面组件。
接下来说一下每个文件的具体作用。
index.js
作为一个单页面的项目,要想实现页面的切换,路由就必不可少。index.js
主要是定义页面的路由,同时,也引入了Ant Design
的样式文件,它会提供一些很不错的默认样式。
import React from 'react';
import ReactDOM from 'react-dom';
import {Router, Route, browserHistory, IndexRoute } from 'react-router';
import App from './app';
import List from './list';
import Add from './add';
import Edit from './edit';
import 'antd/dist/antd.css';
ReactDOM.render(
<Router history={ browserHistory }>
<Route path='/' component={ App }>
<IndexRoute component={ List }></IndexRoute>
<Route path="list" component={ List }></Route>
<Route path="add" component={ Add }></Route>
<Route path='edit/:id' component={ Edit }></Route>
</Route>
</Router>
,
document.getElementById('root')
);
app.js
定义了路由,我们就可以开始页面的基本布局,即父组件。我从Ant Design 的文档中选择了左边是侧边栏,右边是内容显示区的这么一个简单布局方案,并且局部膝盖了它的默认样式,如修改了<Content />
的的minHeight
,让它不管内容多少都基本占满整个屏幕。
同时给侧边栏的选项添加了点击事件,点击时改变样式,并且切换页面。
import React from 'react';
import { Link } from 'react-router';
import { Layout, Menu, Icon } from 'antd';
const { Header, Sider, Content } = Layout;
class App extends React.Component {
constructor(props) {
super(props);
}
state = {
collapsed: false,
};
toggle = () => {
this.setState({
collapsed: !this.state.collapsed,
});
}
select = (item) => { // 点击侧边栏中的各个选项切换页面
// console.log(item.key);
let path = item.key === '1' ? '/' : 'add';
this.props.history.push(path);
}
render() {
return (
<Layout>
<Sider
trigger={null}
collapsible
collapsed={this.state.collapsed}
>
<div className="logo" style={{height: 40}} />
<Menu theme="dark" mode="inline" defaultSelectedKeys={['1']} onClick={ this.select }>
<Menu.Item key="1" >
<Icon type="bars" />
<span className="nav-text">列表</span>
</Menu.Item>
<Menu.Item key="2" >
<Icon type="user-add" />
<span className="nav-text">添加用户</span>
</Menu.Item>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0 }}>
<Icon
className="trigger"
type={this.state.collapsed ? 'menu-unfold' : 'menu-fold'}
onClick={this.toggle}
style={{fontSize: 20, marginLeft: 10, cursor: 'pointer'}}
/>
</Header>
<Content style={{ margin: '24px 16px', padding: 24, background: '#fff', minHeight: 710 }}>
{ this.props.children }
</Content>
</Layout>
</Layout>
);
}
}
export default App;
list.js
列表子组件,放在app.js
的<Content />
中。
首先自定义<App />
组件,在componentWillMount
时,向json-server
用GET
请求之前生成的假数据。
拿到数据之后,通过Ant Design中的<Table />
组件,稍加配置,就能将列表渲染出来。
之后就是在每条数据末尾增加删除和编辑的按钮。给删除按钮绑定了点击事件,一旦点击就发起delete
请求,删除服务器中的数据。而点击编辑按钮,即条状到编辑页面来编辑这条信息。
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router';
import { Table, Input, Popconfirm,Button } from 'antd';
class List extends React.Component {
constructor(props) {
super(props);
this.columns = [{
title: 'id',
dataIndex: 'id'
}, {
title: 'name',
dataIndex: 'name',
width: '20%'
}, {
title: 'email',
dataIndex: 'email',
}, {
title: 'city',
dataIndex: 'city',
width: '20%'
}, {
title: 'operation',
dataIndex: 'operation',
render: (text, record, index) => {
return (
<div className="editable-row-operations">
<Button type='danger' size='small' style={ {marginRight: 10} } ghost onClick={ this.delete.bind(this, text, record, index) }>删除</Button>
<Button type='primary' size='small' ghost onClick={ this.edit.bind(this, text, record, index) }>编辑</Button>
</div>
);
},
}];
this.state = {
list: []
};
}
componentWillMount() {
// 请求数据
axios.get('http://localhost:2000/peopleList')
.then(
res => {
// console.log(res);
this.setState({
list: res.data
})
},
err => console.log(err)
)
}
render() {
const { list } = this.state;
const columns = this.columns;
return (
<div>
<Table bordered dataSource={list} columns={columns} />
</div>
);
}
delete = ( text, record, index) => {
// text 为undefined
// index为分页列表的下标,因为antd-desigin的分页之后下标重新开始, 所以删除的永远是第一个分页的数据,不能用
// record为点击的那条数据对象
// console.log(record)
// console.log(text)
// 寻找该条数据的实际下标
let itemIndex = 0;
for (let i = 0; i < this.state.list.length; i++) {
if (this.state.list[i].id === record.id) {
itemIndex = i;
}
}
if (confirm(`确认将${ record.name }移除吗?`)) {
axios.delete("http://localhost:2000/peopleList/" + record.id)
.then(
res => {
console.log(res.data); // 删除成功的话返回一个空数组
if (res.data) {
this.state.list.splice(itemIndex, 1);
this.setState({
list: this.state.list
})
}
},
err => console.log(new Error(err))
)
}
}
edit = ( text, record, index) => {
// 寻找该条数据的实际下标
let itemIndex = 0;
for (let i = 0; i < this.state.list.length; i++) {
if (this.state.list[i].id === record.id) {
itemIndex = i;
}
}
this.props.history.push('edit/' + this.state.list[itemIndex].id);
}
}
export default List;
效果如下图:
edit.js
点击编辑按钮之后,页面会跳转到编辑页,该页面用到了Ant Design封装的表单组件,通过react-router
传递过来的数据,即可在组件render前请求数据,之后将原来的用户信息渲染的页面。
然后编辑之后,对`json-server`发起`PUT`请求,在请求URL中加上id值,即可修改对应用户的信息。
import React from 'react';
import axios from 'axios';
import { Form, Icon, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
class Edit extends React.Component {
constructor(props) {
super(props);
this.state = {
item: {}
}
}
// 请求该用户的原始数据
componentWillMount() {
axios.get('http://localhost:2000/peopleList/' + this.props.params.id)
.then(
res => {
// console.log(res.data);
this.setState({
item: res.data
});
},
err => console.log(new Error(err))
)
}
render() {
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
姓名:
<Input prefix={<Icon type="user" style={{ fontSize: 13 }} />} placeholder="姓名" value={this.state.item.name} onChange={ (e) => { this.change(e, 'name') } }/>
</FormItem>
<FormItem>
邮箱:
<Input prefix={<Icon type="contacts" style={{ fontSize: 13 }} />} type="text" placeholder="请输入邮箱" value={ this.state.item.email } onChange={ (e) => { this.change(e, 'email') } }/>
</FormItem>
<FormItem>
城市:
<Input prefix={<Icon type="compass" style={{ fontSize: 13 }} />} type="text" placeholder="城市" value={ this.state.item.city } onChange={ (e) => { this.change(e, 'city') } }/>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button" onClick={ this.submit }>
确认修改
</Button>
</FormItem>
</Form>
);
}
// 改变输入框内容
change = (e, key) => {
this.state.item[key] = e.target.value;
this.setState({
item: this.state.item
})
}
submit = () => {
// 请求接口修改数据
axios.put('http://localhost:2000/peopleList/' + this.props.params.id, {
...this.state.item
})
.then(
res =>{
console.log(res.data);
if (res.data) {
alert('修改成功!');
this.props.history.push('/');
}
},
err => console.log(err)
)
}
}
export default Edit;
效果图:
add.js
这个组件和编辑页面类似,点击侧边栏的增加用户选项即可进入。
只不过进来的时候表单的数据都为空。
Ant Design在<Input />
组件中有个让人不爽的地方,在这个组件用ref
能拿到组件的一些属性方法,但是取不到input框的value,所以这里需要绕一点弯路。
点击保存,会向json-server
发送POST
请求,添加数据。
还有个需要注意的点: 添加的数据不需要指定Id,json-server
会为我们自动添加。
代码逻辑和效果图与edit.js
类似。
以上,我们的项目基本完成。
小结
通过这个小项目,我们可以学到以下几点知识:
- 通过
create-react-app
脚手架快速配置React的开发环境。 - 通过
json-server
能让我们前端开发人员模拟完成get/post/put/delete
请求。 - 通过
faker
快速生成json数据,用于开发,测试。 - 通过
Ant Design
中的组件快速开发我们的项目。