提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
react组件封装
一、基础组件封装
1.1.Input
import { Input, message } from "antd";
const DeliveryInput = ({
value,
onChange,
maxNum,
item,
handleOrderList,
}: any) => {
const [messageApi, contextHolder] = message.useMessage();
const handleChange = (e: any) => {
const inputValue = e.target.value;
if (/^[1-9][0-9]*$/.test(inputValue) && inputValue.length <= 4) {
if (maxNum) {
if (Number(inputValue) > maxNum) {
messageApi.warning("已经是最大值了!");
} else {
onChange(Number(inputValue));
handleOrderList &&
handleOrderList(
item.dataIndex,
item.entity?.itemId,
inputValue,
item.entity,
);
}
} else {
onChange(Number(inputValue));
handleOrderList &&
handleOrderList(
item.dataIndex,
item.entity?.itemId,
inputValue,
item.entity,
);
}
} else if (inputValue === "") {
onChange("");
handleOrderList &&
handleOrderList(
item.dataIndex,
item.entity?.itemId,
inputValue,
item.entity,
);
}
};
return (
<>
{contextHolder}
<Input
style={{
width: "100%",
height: "100%",
color: "#F29D39",
}}
type="number"
value={value}
onChange={handleChange}
placeholder={"请输入货期"}
/>
</>
);
};
export default DeliveryInput;
1.2.Loading
import { styled } from "@umijs/max";
import { Spin } from "antd";
import React from "react";
const LoadingBox = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
zindex: 999;
.content {
padding: 50px;
background: rgba(0, 0, 0, 0);
border-radius: 4px;
}
`;
interface ILoading {
size?: "small" | "default" | "large";
spinning?: boolean;
boxStyle?: React.CSSProperties | undefined;
loadingText?: string;
}
/**
*
* @param size loading大小, small default large
* @param spinning 是否为加载中状态
* @param boxStyle 容器自定义样式
* @param loadingText 加载提示文本
*/
const Loading: React.FC<ILoading> = ({
size,
spinning,
boxStyle,
loadingText,
}): React.ReactElement => {
return (
<LoadingBox style={boxStyle}>
<Spin spinning={spinning} size={size} tip={loadingText}>
{spinning ? <div className="content" /> : <></>}
</Spin>
</LoadingBox>
);
};
export default Loading;
1.3.Upload(图片限制,可选裁切)
import { PlusOutlined } from "@ant-design/icons";
import type { UploadFile, UploadProps } from "antd";
import { Image as ImageAntd, Upload, message } from "antd";
import ImgCrop from "antd-img-crop";
import { RcFile } from "antd/es/upload";
import { useState } from "react";
const getBase64 = (img: RcFile, callback: (url: string) => void) => {
const reader = new FileReader();
reader.addEventListener("load", () => callback(reader.result as string));
reader.readAsDataURL(img);
};
const base64ToBlob = (url: any, imageType: string | undefined) => {
const arr = url.split(",");
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: imageType });
};
/**
*
* @param setFileFormData 设置接口FormData数据
* @param setBase64ToBlobObj 设置接口FormData的图片参数setBase64ToBlob及fileName
* @param fileList 接口返回的图片列表
* @param uploadButtonText 上传按钮文字
* @param restrictWidth 宽度限制
* @param restricHeight 高度限制
* @param type formData自命名图片名字前缀
* @param size 图片大小限制
* @param aspectWidth 图片裁剪比例宽度设置
* @param sizeHeight 图片裁剪比例高度设置
*/
const UploadImage = ({
setFileFormData,
setBase64ToBlobObj,
id,
fileList: fileListArr,
uploadButtonText,
restrictWidth,
restricHeight,
type,
size,
aspectWidth,
sizeHeight,
}: any) => {
const [messageApi, contextHolder] = message.useMessage();
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState("");
const [fileList, setFileList] = useState<UploadFile[]>(fileListArr || []);
const validateImageSize = (file: File) => {
return new Promise((resolve, reject) => {
getBase64(file as RcFile, async (url) => {
const image = new Image();
image.onload = () => {
const { width, height } = image;
if (width === restrictWidth && height === restricHeight) {
resolve(true);
} else {
messageApi.error("图片尺寸不符合要求,请重新上传");
resolve(false);
}
};
image.onerror = reject;
image.src = url;
});
});
};
// 限制图片
const beforeUpload: any = async (file: RcFile) => {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
if (!isJpgOrPng) {
messageApi.error("请上传JPG/PNG图片!");
}
const isLtSizeMB = file.size / 1024 / 1024 < (size || 6);
if (!isLtSizeMB) {
messageApi.error(`请上传大小为${size || 6}MB以内的图片!`);
}
if (restrictWidth || restricHeight) {
return isJpgOrPng && isLtSizeMB;
} else {
const limitSize = await validateImageSize(file);
return isJpgOrPng && isLtSizeMB && limitSize;
}
};
const handleChange: UploadProps["onChange"] = (info) => {
if (info.file?.originFileObj) {
setFileList(info.fileList);
getBase64(info.file.originFileObj as RcFile, async (url) => {
setPreviewImage(url);
const formData = new FormData();
if (id) formData.append("id", id);
formData.append(
type,
base64ToBlob(url, info.file.type),
`${type}—` + Date.now() + "." + info.file.type?.split("/")[1],
);
setFileFormData?.(formData);
setBase64ToBlobObj?.({
base64ToBlob: base64ToBlob(url, info.file.type),
fileName:
`${type}—` + Date.now() + "." + info.file.type?.split("/")[1],
});
});
}
};
const handlePreview = async () => {
if (fileList?.[0]?.url) {
setPreviewImage(fileList?.[0]?.url);
}
setPreviewOpen(true);
};
const uploadButton = (
<button style={{ border: 0, background: "none" }} type="button">
<PlusOutlined />
<div style={{ marginTop: 8, fontWeight: 400 }}>
{uploadButtonText || "上传LOGO"}
</div>
</button>
);
return (
<>
{contextHolder}
<ImgCrop
rotationSlider
// aspectSlider // 图片旋转
aspect={aspectWidth || 1 / sizeHeight || 1}
>
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader"
fileList={fileList}
action="/upload.do"
beforeUpload={beforeUpload}
onChange={handleChange}
onPreview={handlePreview}
onRemove={() => {
setBase64ToBlobObj?.(null);
setFileFormData?.(null);
setFileList([]);
setPreviewImage("");
}}
>
{fileList.length >= 1 ? null : uploadButton}
</Upload>
</ImgCrop>
{previewImage && (
<ImageAntd
wrapperStyle={{ display: "none" }}
preview={{
visible: previewOpen,
onVisibleChange: (visible) => setPreviewOpen(visible),
// afterOpenChange: (visible) => !visible && setPreviewImage(""),
}}
src={previewImage}
/>
)}
</>
);
};
export default UploadImage;
总结
以上就是今天要讲的内容,本文主要记录开发常用的React封装的组件。
愿:平安顺遂!