公司接了一个 Ant Design Pro 的项目,后台接口已经有了,需要搭建前端。因为是一个项目,所以这两个功能就一起讲了。
1、category_name(获取图片类型接口)
发送:无
接收:list(类型列表)
2、upload(上传接口):
发送:image_name(文件名)、image_data(base64数据)
接收:pic_url(图片在服务器上的地址)
3、upload_confirm(提交接口):
发送:name(图片标题)、category(图片类型)和pic_url(上传接口返回的地址)
接收:status(是否提交成功)
一、下载ant design pro模板。
官方文档https://pro.ant.design/docs/getting-started-cn
使用命令:
$ git clone --depth=1 https://github.com/ant-design/ant-design-pro.git my-project
$ cd my-project
安装依赖
$ npm install
打开网站模板
$ npm start
二、添加菜单项
三、添加路由
四、添加页面
在 'src/routes/Dashboard' 下创建 Up.js 文件,这就是我们的页面。
接下来,我们在ant design官方文档查看我们需要用到的组件:Form表单、Select选择器、Input输入框、Upload组件。仿照案例编在 Up.js 写如下代码:(可直接复制)
import React, { PureComponent } from 'react';
import { Form, Select, Input, Button, Upload, Icon } from 'antd';
class Up extends PureComponent {
state = {
loading: false
};
render() {
const Option = Select.Option;
const FormItem = Form.Item;
//上传图片的base64编码
const imageUrl = this.state.imageUrl;
//获取表单输入值的方法
const { getFieldProps } = this.props.form;
//表单项栅格设置
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
//下拉列表项
const children = [];
for (let i = 0; i < 36; i++) {
children.push();
}
//上传图片按钮
const uploadButton = (
Upload
);
return (
);
}
}
//Form.create()方法是将this.props.form填进来,使能获取用户输入的值
const UpForm = Form.create()(Up);
export default UpForm;
效果图:
五、填充下拉列表
在加载页面时,就需要请求category(图片类型)的接口。仿照案例,我们可以使用antd pro自带的dva通过模型来请求数据。还记得我们在第三步定义的路由吗,里面就包含了我们要用的模型 "category" ,因此我们需要在 'src/models' 文件夹下创建一个"category.js"模型,代码如下:
//这是我们要请求的api
import { cateList } from '../services/api';
export default {
namespace: 'category',
state: {
cate: [],
},
effects: {
*cate(_, { call, put }) {
//请求api
const response = yield call(cateList);
//把返回的参数'payload'给下面的'cateList'
yield put({
type: 'cateList',
payload: Array.isArray(response) ? response : [],
});
}
},
reducers: {
//把返回的参数赋值给'state'里的'cate'
cateList(state, action) {
return {
...state,
cate: action.payload,
};
},
},
};
接下来,我们导入的api是要自己定义的,所以去 'src/service/api.js' 文件中定义api。
需要注意的是,我的api本来是:http://XX.94.82.153:8003/category_name/ ,为什么这里写了 '/myApi/category_name' 呢?因为这是跨域请求,需要修改代理,方法如下:
模型方面就已经弄好了。怎么样?是不是很心累??是的!!
接下来我们连接这个模型,并调用方法,获取数据。回到Up.js,做以下几步完善。说实话这些注释是我百度后猜测的功能...如有错误欢迎指正!感谢!
整体的代码如下:
import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Form, Select, Input, Button, Upload, Icon } from 'antd';
@connect(({ category }) => ({
category,
}))
class Up extends PureComponent {
state = {
loading: false
};
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'category/cate',
});
}
render() {
const {
category: { cate }
} = this.props;
const Option = Select.Option;
const FormItem = Form.Item;
//上传图片的base64编码
const imageUrl = this.state.imageUrl;
//获取表单输入值的方法
const { getFieldProps } = this.props.form;
//表单项栅格设置
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
//下拉列表项
const children = [];
for (let i = 0; i < cate.length; i++) {
children.push();
}
//上传图片按钮
const uploadButton = (
Upload
);
return (
);
}
}
const UpForm = Form.create()(Up);
export default UpForm;
打开网页就有下拉列表啦~
六、上传图片
首先要知道上传图片的流程:
1、选择图片。
2、上传图片到服务器,服务器返回图片地址。
3、将填入的图片名称、图片类型和返回的图片地址提交到服务器。
第一步,Upload组件已经帮我们做了。
第二步,需要调用开头提到的upload方法
upload(上传接口):
发送:image_name(文件名)、image_data(base64数据)
接收:pic_url(图片在服务器上的地址)
所以我们要做的就是获取文件名、将图片转64编码、发送请求、接收返回数据。
由于接口要求发送的是json格式的数据,我们不能用自带的action方法,因为它传递的参数是formdata格式的。但action又是必选参数,所以写为空。这里可以调用的方法是beforeUpload,它在action之前调用,此处可以代替action。
{imageUrl ? : uploadButton}
方法后面有个 .bind(this) 是用来传递真正的 this。beforeUpload方法如下,参数中的file是自带过去上传的图片信息。通过getBase64方法获取到编码imageUrl,然后用fetch发送post请求,通过 .then() 获取返回的图片地址。
beforeUpload(file){
this.getBase64(file, (imageUrl) =>
{
this.setState({
imageUrl,
loading: false
})
if(imageUrl){
let apirul = '/myApi/wallpaper_uploads/';
let u = imageUrl.substring(imageUrl.indexOf(',') + 1, imageUrl.length)
let data = {
image_name:file.name,
image_data:u
}
fetch(apirul,{
method: 'post',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data),
})
.then(res => res.json())
.then(res => {
this.setState({pic_url:res.pic_url});
})
}
});
return 1;
}
其中,getBase64方法是将图片编码,调用回调函数是为了确保执行完回调函数再进行一步。
getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
此外,还有一个 onChange 函数,这个是用来判断图片有没有上传成功的。
handleChange = (info) => {
if (info.file.status === 'uploading') {
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
this.setState({
loading: false,
});
}
}
这样,当选择图片后,查看网络:
第三步,获取到图片地址后,还要将表单中填入的图片标题和图片类型一起提交,调用upload_confirm接口。
upload_confirm(提交接口):
发送:name(图片标题)、category(图片类型)和pic_url(上传接口返回的地址)
接收:status(是否提交成功)
如何获取每个formitem的值呢?
在这里,我们已经在结尾使用了如下方法。
const UpForm = Form.create()(Up);
export default UpForm;
这个方法使得我们可以在return前获取这个值。
const { getFieldProps } = this.props.form;
然后在每一个formitem中添加:
{...getFieldProps('name')}
括号中的名称是自己定的,相当于 form 中的 name。
最后,还要添加 onSubmit 方法:
handleSubmit = (e) => {
let apirul = '/myApi/wallpaper_uploads_confirm/';
//接口地址
let data = {
name:this.props.form.getFieldsValue().name,
category:this.props.form.getFieldsValue().category,
pic_url:this.state.pic_url
}
fetch(apirul,{
method: 'post',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data),
})
.then(function (res) {
return res.json();
})
.then(res => {
console.log(res);
})
}
至此,上传图片完成。完整代码如下:
import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Form, Select, Input, Button, Upload, Icon } from 'antd';
const Option = Select.Option;
@connect(({ category }) => ({
category,
}))
class Up extends PureComponent {
state = {
loading: false,
file_name:''
};
componentDidMount() {
const { dispatch } = this.props;
dispatch({
type: 'category/cate',
});
}
getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
handleChange = (info) => {
if (info.file.status === 'uploading') {
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
this.setState({
loading: false,
});
}
}
beforeUpload(file){
this.getBase64(file, (imageUrl) =>
{
this.setState({
imageUrl,
loading: false
})
if(imageUrl){
let apirul = '/myApi/wallpaper_uploads/';
let u = imageUrl.substring(imageUrl.indexOf(',') + 1, imageUrl.length)
let data = {
image_name:file.name,
image_data:u
}
fetch(apirul,{
method: 'post',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data),
})
.then(res => res.json())
.then(res => {
this.setState({pic_url:res.pic_url});
})
}
});
return 1;
}
handleSubmit = (e) => {
let apirul = '/myApi/wallpaper_uploads_confirm/';
//接口地址
let data = {
name:this.props.form.getFieldsValue().name,
category:this.props.form.getFieldsValue().category,
pic_url:this.state.pic_url
}
fetch(apirul,{
method: 'post',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data),
})
.then(function (res) {
return res.json();
})
.then(res => {
console.log(res);
})
}
render() {
const {
category: { cate }
} = this.props;
const children = [];
for (let i = 0; i < cate.length; i++) {
children.push();
}
const FormItem = Form.Item;
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
const uploadButton = (
Upload
);
const imageUrl = this.state.imageUrl;
const { getFieldProps } = this.props.form;
return (
);
}
}
const UpForm = Form.create()(Up);
export default UpForm;