Ant Design Pro 获取下拉列表、图片上传

公司接了一个 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(<Option key={i.toString(36) + i}>{i.toString(36) + i}</Option>);
        }
        //上传图片按钮
        const uploadButton = (
            <div>
              <Icon type={this.state.loading ? 'loading' : 'plus'} />
              <div className="ant-upload-text">Upload</div>
            </div>
        );

        return (
            <Form>
                <FormItem {...formItemLayout} label="图片名称" >
                    <Input {...getFieldProps('name')} style={{ width:"300px" }} />
                </FormItem>

                <FormItem {...formItemLayout} label="图片类型" >
                    <Select {...getFieldProps('category')} style={{ width:"300px" }} >
                        {children}
                    </Select>
                </FormItem>

                <FormItem {...formItemLayout} label="上传图片" >
                  <Upload
                    {...getFieldProps('pic_url')}
                    listType="picture-card"
                    showUploadList={false}
                    action=""
                    >
                    {imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
                  </Upload>
                </FormItem>

                <FormItem wrapperCol={{ span: 12, offset: 6 }} >
                  <Button type="primary" htmlType="submit">提交</Button>
                </FormItem>
            </Form>
        );
    }
}
//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(<Option key={i} value={ cate[i].category_name }>{ cate[i].category_name }</Option>);
        }
        //上传图片按钮
        const uploadButton = (
            <div>
              <Icon type={this.state.loading ? 'loading' : 'plus'} />
              <div className="ant-upload-text">Upload</div>
            </div>
        );

        return (
            <Form>
                <FormItem {...formItemLayout} label="图片名称" >
                    <Input {...getFieldProps('name')} style={{ width:"300px" }} />
                </FormItem>

                <FormItem {...formItemLayout} label="图片类型" >
                    <Select {...getFieldProps('category')} style={{ width:"300px" }} >
                        {children}
                    </Select>
                </FormItem>

                <FormItem {...formItemLayout} label="上传图片" >
                  <Upload
                    {...getFieldProps('pic_url')}
                    listType="picture-card"
                    showUploadList={false}
                    action=""
                    >
                    {imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
                  </Upload>
                </FormItem>

                <FormItem wrapperCol={{ span: 12, offset: 6 }} >
                  <Button type="primary" htmlType="submit">提交</Button>
                </FormItem>
            </Form>
        );
    }
}
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。

<Upload
    {...getFieldProps('pic_url')}
    listType="picture-card"
    className="avatar-uploader"
    showUploadList={false}
    action=""
    beforeUpload={this.beforeUpload.bind(this)}
    onChange={this.handleChange}
>
    {imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
</Upload>

方法后面有个 .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(<Option key={i} value={ cate[i].category_name }>{ cate[i].category_name }</Option>);
        }

        const FormItem = Form.Item;
        const formItemLayout = {
            labelCol: { span: 6 },
            wrapperCol: { span: 14 },
        };

        const uploadButton = (
            <div>
              <Icon type={this.state.loading ? 'loading' : 'plus'} />
              <div className="ant-upload-text">Upload</div>
            </div>
        );
        const imageUrl = this.state.imageUrl;
        const { getFieldProps } = this.props.form;
        
        return (
            <Form onSubmit={this.handleSubmit} >
                <FormItem
                {...formItemLayout}
                label="图片名称"
                >
                    <Input {...getFieldProps('name')} placeholder="Please input name" style={{ width:"300px" }} />
                </FormItem>
                <FormItem
                {...formItemLayout}
                label="图片类型"
                >
                    <Select {...getFieldProps('category')} placeholder="Please select a category" style={{ width:"300px" }} >
                        {children}
                    </Select>
                </FormItem>
                <FormItem
                {...formItemLayout}
                label="上传图片"
                >
                  <Upload
                    {...getFieldProps('pic_url')}
                    listType="picture-card"
                    className="avatar-uploader"
                    showUploadList={false}
                    action=""
                    beforeUpload={this.beforeUpload.bind(this)}
                    onChange={this.handleChange}
                  >
                    {imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}

                  </Upload>
                </FormItem>
                <FormItem
                wrapperCol={{ span: 12, offset: 6 }}
                >
                  <Button type="primary" htmlType="submit">提交</Button>
                </FormItem>

            </Form>
        );
    }
}

const UpForm = Form.create()(Up);

export default UpForm;

猜你喜欢

转载自blog.csdn.net/qq_33514421/article/details/81507354
今日推荐