从零开始,搭建一个简单的购物平台(五):https://blog.csdn.net/time_____/article/details/105437534
项目源码(持续更新):https://gitee.com/DieHunter/myCode/tree/master/shopping
在第四篇文章中实现了服务端的文件上传以及添加用户的后端功能,并进行了测试,这篇文章主要实现前端上传头像和添加用户的功能
首先我们引入antd中的文件上传组件,并将其封装到我们的组件中
我们限制用户只能上传一张图片,其中上传组件中的action表示上传的路径,也就是我们在第四篇中的测试上传文件地址,name是文件标识名,data是传的参数,这里我们是用的token
import React from "react"; import { Upload, message } from "antd"; import { PlusOutlined } from "@ant-design/icons"; import config from "../../config/config"; let { UploadName, Agreement, BaseUrl, ServerPort, Path, UploadKey, StorageName, } = config; export default class UpdataPic extends React.Component { state = { fileList: [], }; handleChange = ({ fileList, file }) => { this.setState({ fileList }); if (file["response"] && file.status == "done") { let res = file["response"]; message.success(res.msg); } if (file["status"] == "removed") { } }; render() { const { fileList } = this.state; const uploadButton = ( <div> <PlusOutlined /> <div className="ant-upload-text">上传头像</div> </div> ); return ( <div className="clearfix"> <Upload action={Agreement + BaseUrl + ServerPort + Path + UploadName.headPic} name={UploadKey.headKey} listType="picture-card" fileList={fileList} onChange={this.handleChange} data={{ token: this.$utils.getStorage(StorageName.token) }} > {fileList.length >= 1 ? null : uploadButton} </Upload> </div> ); } }
然后我们在某个页面引入该组件试试效果
上传功能实现后,我们就可以开始实现添加用户了
新增用户,我打算放到右边的抽屉组件中,也就是Drawer组件,将form表单嵌入至抽屉中(修改用户和新增用户有着类似之处,我们做修改用户信息直接在新增用户Drawer中赋予form初始值即可)
有几个注意点,1.antd的form需要使用React.createRef()将组件加载。2.表单数据赋予初始值时,需要调表单的this.formRef.current.setFieldsValue()方法,然而这里有个坑,当Drawer组件显示时,form组件还未载入,这时如果直接赋值,就会因异步导致赋值不成功,解决方法(官方给的处理方式是用redux全局管理,我这里是用生命周期函数解决的):首先在Drawer组件中启用预加载功能(forceRender,预渲染 Drawer 内元素),然后在生命周期(componentDidUpdate)中获取state中的值,调用this.formRef.current.setFieldsValue()即可(修改用户信息与此相同)
import React from "react"; import Mail from "../../config/mail"; import { Drawer, Form, Button, Col, Row, Input, Select, Radio, Cascader, message, } from "antd"; import config from "../../config/config"; import City from "../../config/city"; import UpdataPic from "../updata/updata"; const { ServerApi, StorageName, FilePath } = config; const { Option } = Select; export default class ListDrower extends React.Component { formRef = React.createRef(); state = { visible: false, record: {}, }; componentDidMount() { this.props.onDrowerRef(this); } componentDidUpdate() { this.formRef.current.setFieldsValue(this.state.record); } showDrawer = () => {//显示Drawer this.setState({ formType: "add", visible: false, record: { sex: "man", userType: "user", mailurl: "@qq.com", }, }); this.setState({ visible: true, }); }; onClose = () => {//隐藏Drawer this.formRef.current.resetFields(); this.setState({ visible: false, record: null, }); }; getPic = (data) => {//上传头像后刷新表单头像信息 this.formRef.current.setFieldsValue({ headPic: data.headPath, }); }; delPic = () => {//删除头像后同时删除表单图片信息 this.formRef.current.setFieldsValue({ headPic: null, }); }; sendData(val) {//提交用户信息 val.token = this.$utils.getStorage(StorageName.token); let data = this.$crypto.setCrypto(val); let _t = this; this.$axios .post(ServerApi.user.addUser, { crypto: data }) .then((res) => { switch (res.result) { case 1: message.success(res.msg); _t.onClose(); _t.props.getUserList(); break; case 0: message.warning(res.msg); break; default: // message.warning(res.msg); break; } }) .catch((err) => { message.error("操作失败"); }); } render() { return ( <Drawer title="新增用户" width={720} onClose={this.onClose} visible={this.state.visible} forceRender //加上预加载,防止表单异步生成,导致this.formRef.current为空 bodyStyle={{ paddingBottom: 80 }} footer={ <div style={{ textAlign: "right", }} > <Button onClick={this.onClose} style={{ marginRight: 20 }}> 取消 </Button> </div> } > <Form layout="vertical" hideRequiredMark ref={this.formRef} onFinish={this.sendData.bind(this)} > <Row gutter={16}> <Col span={10}> <Form.Item name="headPic" label="头像"> <UpdataPic onUpdateRef={(child) => { this.updateChild = child; }} picTarget={this.getPic} picDelete={this.delPic} ></UpdataPic> </Form.Item> </Col> <Col span={10}> <Form.Item name="userType" label="用户类型" rules={[{ required: true, message: "请选择用户类型" }]} > <Radio.Group buttonStyle="solid"> <Radio.Button value="admin">管理员</Radio.Button> <Radio.Button value="user">用户</Radio.Button> </Radio.Group> </Form.Item> </Col> </Row> <Row gutter={16}> <Col span={12}> <Form.Item name="username" label="用户名" rules={[{ required: true, message: "请输入用户名" }]} > <Input placeholder="请输入用户名" allowClear /> </Form.Item> </Col> <Col span={12}> <Form.Item name="password" label="密码" rules={[{ required: true, message: "请输入密码" }]} > <Input.Password type="password" placeholder="请输入密码" allowClear /> </Form.Item> </Col> </Row> <Row gutter={16}> <Col span={5}> <Form.Item name="sex" label="性别" rules={[{ required: true, message: "请选择性别" }]} > <Radio.Group buttonStyle="solid"> <Radio.Button value="man">男</Radio.Button> <Radio.Button value="woman">女</Radio.Button> </Radio.Group> </Form.Item> </Col> <Col span={16}> <Form.Item label="邮箱"> <Input.Group compact> <Form.Item name="mailaddress" rules={[{ required: true, message: "请输入正确邮箱" }]} > <Input defaultValue="" allowClear /> </Form.Item> <Form.Item name="mailurl" rules={[{ required: true, message: "请选择邮箱类型" }]} > <Select onChange={this.changeMail} style={{ width: 150 }}> {(() => { return Mail.address.map((item) => { return ( <Option key={item.mail} value={item.mail}> {item.mail} </Option> ); }); })()} </Select> </Form.Item> </Input.Group> </Form.Item> </Col> </Row> <Row gutter={20}> <Col span={16}> <Form.Item label="收货地址" required={false}> <Input.Group compact> <Form.Item name="alladdress" // rules={[{ required: true, message: "请选择收货地址" }]} > <Cascader options={City} placeholder="请选择收货地址" /> </Form.Item> <Form.Item name="address" // rules={[{ required: true, message: "请填写收货地址" }]} > <Input placeholder="请输入详细地址" allowClear /> </Form.Item> </Input.Group> </Form.Item> </Col> </Row> <Row gutter={16}> <Col span={24}> <Form.Item name="descript" label="个性签名"> <Input.TextArea rows={4} placeholder="个性签名" /> </Form.Item> </Col> </Row> <Form.Item> <Button type="primary" htmlType="submit" className="login-form-button" > 提交 </Button> </Form.Item> </Form> </Drawer> ); } }
最后,我们请求服务端试一试
总结
React是一个基于view显示层实现的dom优化框架,其对全局状态管理插件redux是将部分共享变量全局化,就相当于在原生window作用域中定义全局变量,虽然有一定的便捷,但是能不用的地方,最好是少用