UNPKG

2.69 kBJavaScriptView Raw
1import React, { useReducer } from "react";
2import styled from "styled-components";
3import axios from "axios";
4
5const initState = {
6 percent: 0,
7};
8const reducer = (state, action) => {
9 return { ...state, ...action };
10};
11
12/**
13 * ----------------------------------------
14 * 上传文件和回显文件
15 * @param {String} value - 文件路径
16 * @param {Function} onChange
17 * @param {String} [url] - 接口地址
18 * @param {Object} [headers] - 设置请求头
19 * @param {String} [accept=""] - 文件格式
20 * @param {String} [title] - 文字提示
21 * ----------------------------------------
22 */
23export default function UploadInput({
24 url = "",
25 value = "",
26 accept = "",
27 onChange,
28 title = "选择文件",
29 headers,
30}) {
31 const [state, dispatch] = useReducer(reducer, initState);
32 const loading = state.percent > 0 && state.percent <= 100;
33 // eslint-disable-next-line no-useless-escape
34 const matchFileName = value.match(/[^\/]+$/);
35 const fileName = matchFileName ? matchFileName[0] : "";
36
37 const _onChange = async e => {
38 const file = e.target.files[0];
39 const form = new FormData();
40 form.append("file", file);
41 const res = await axios.post(url, form, {
42 headers: {
43 "Content-Type": "multipart/form-data;charset=UTF-8",
44 ...headers,
45 },
46 onUploadProgress: e => {
47 const percent = ((e.loaded / e.total) * 100) | 0;
48 dispatch({ percent });
49 },
50 });
51 const filePath = res.data.data;
52 setTimeout(() => {
53 dispatch({ percent: 0 });
54 onChange(filePath);
55 }, 300);
56 };
57
58 return (
59 <>
60 <SBox>
61 {loading ? (
62 <span style={{ color: "#ff0000" }}>
63 正在上传({state.percent}%)...
64 </span>
65 ) : (
66 <SLabel>
67 <div style={{ height: "100%" }}>
68 {title}
69 <span style={{ color: "gray", fontSize: "12px" }}>
70 (限制30M以内)
71 </span>
72 </div>
73 <input
74 accept={accept}
75 type="file"
76 onChange={_onChange}
77 style={{ width: "1px", display: "none" }}
78 />
79 </SLabel>
80 )}
81 </SBox>
82 <SFiles>{fileName}</SFiles>
83 </>
84 );
85}
86
87const SBox = styled.div`
88 display: flex;
89 align-items: center;
90 justify-content: center;
91 border: 1px dashed #d4d4d4;
92 background-color: #f3f3f3;
93 height: 50px;
94 line-height: 50px;
95`;
96
97const SLabel = styled.label`
98 width: 100%;
99 height: 50px;
100 line-height: 50px;
101 color: #2a2aa0;
102 display: flex;
103 flex-direction: column;
104 align-items: center;
105 justify-content: center;
106`;
107const SFiles = styled.div`
108 margin-top: 3px;
109 color: #0e41ad;
110`;