最近公司前端缺人手,所以我厚着脸皮做起了半个前端,在运营后台项目上实现一些小的需求。
运营后台用的前端框架是阿里的飞冰[1]。
在写文件上传的时候,我发现项目中每个上传的地方都有如下校验文件是否符合要求的代码:
<Upload.Card
beforeUpload={(info) => {
return new Promise((res, rej) => {
const reader = new FileReader();
reader.onload = () => {
const img = new Image();
img.onload = () => {
if (img.width === 702 && img.height === 172) {
res();
} else {
Message.error("请上传702px*172px的图片");
rej();
}
};
img.src = reader.result;
};
reader.readAsDataURL(info);
});
}}
/>
结合飞冰文档,简单阅读一下代码可以知道,beforeUpload 是在上传文件前做一些校验操作。
在我们的业务中,很多地方都需要上传文件,而且对文件的校验逻辑也各有不同。
但总结下来,上传文件的校验无外乎文件的 大小、尺寸 和 类型,其中 类型 可以由 Upload 组件的 accept 参数进行控制。
做为有一点点代码洁癖的人,看到分散在各处的逻辑类似的 beforeUpload 函数,自然就动起了重构一下的想法。
说到逻辑复用,React 中的 高阶组件[2] 当仁不让。
首先,我们要抽离的逻辑有两部分:
-
FileReader 和 Image 读文件的逻辑。 -
(文件读取完毕后) 判断文件尺寸和大小的逻辑。
其中,读文件的逻辑是所有上传的地方可共用的;判断文件尺寸和大小的逻辑在不同的地方需求有所不同,所以需要一个外传函数(用户提供)。如此,高阶组件的形象就出来了。
假设高阶组件函数名叫 withFile,则:
function withFile(Upload, validate) {
return function fileUpload(props) {
return (
<Upload
{...props}
beforeUpload={(file) => {
return new Promise((res) => {
const img = new Image();
img.onload = () => {
res(
validate({
width: img.width,
height: img.height,
size: file.size,
})
);
URL.revokeObjectURL(img.src);
};
img.src = URL.createObjectURL(file);
});
}}
/>
);
};
}
有两点要注意的:
-
我们没有使用官方示例中的 FileReader 来读取文件,而是用了更方便的 URL.createObjectURL。 -
validate 参数是独立出去的文件校验函数。
有了以上封装,文章开头的代码可以做如下改动:
const FileUpload = withFile(Upload.Card, (info) => {
if (info.width === 702 && info.height === 172) {
return true;
}
Message.error("请上传702px*172px的图片");
return false;
});
<FileUpload />;
在使用时,我们最关注的是文件校验,而我们的封装也体现了这一点;代码也变得简单又易读了。
你觉得呢?
参考资料
飞冰框架: https://ice.work
[2]
高阶组件: https://reactjs.org/docs/higher-order-components.html
– END –
原文始发于微信公众号(背井):编写可复用的文件上传高阶组件(结合阿里飞冰)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/246819.html