从零开始,搭建一个简单的购物平台(六)
从零开始,搭建一个简单的购物平台(五):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作用域中定义全局变量,虽然有一定的便捷,但是能不用的地方,最好是少用