基于业务场景下的图片/文件上传方案总结

简介: 图片/文件上传组是企业项目开发中必不可少的环节之一, 但凡涉及到用户模块的都会有图片/文件上传需求, 在很多第三方组件库(ant desigin, element ui)中它也是基础组件之一. 接下来笔者就来带大家从零实现一款图片/文件上传组件以及扩展出更强大的上传组件.

网络异常,图片无法展示
|

前言


图片/文件上传组是企业项目开发中必不可少的环节之一, 但凡涉及到用户模块的都会有图片/文件上传需求, 在很多第三方组件库(ant desigin, element ui)中它也是基础组件之一. 接下来笔者就来带大家从零实现一款图片/文件上传组件以及扩展出更强大的上传组件.


你将收获


  • 常用的图片上传功能实现方案
  • 手写一个图片/文件上传组件
  • 如何将裁剪功能集成到上传组件中
  • 内容平台/可视化平台下的图片自治方案
  • 如何扩展出更强大的图片上传方案


正文


作为一名前端工程师, 解决项目问题是我们的基本职责之一, 我们可以利用已掌握的知识去解决项目开发中的问题和需求, 这也是我们职业生涯必将经历的第一个阶段,即——适应期. 如果我们想继续晋升, 我们就需要不断的打怪升级,掌握各种技能, 这样我们才能在未来遇到问题时采用最佳的方案高效的解决问题, 也就是第二个阶段——发展期.


为了更快的进入发展期, 我们需要不断的提升自己的技术深度和广度, 能纵向考虑到问题的本质也能横向的对问题提出多种解决方案, 最终选择一种最优方案来实现. 要实现这一点,我们需要对问题做深度思考和复盘, 接下来笔者将介绍几种常用的图片上传方案,来扩展大家的广度.


1. 常用的图片上传方案



web1.0时代开始, 我们用的最多的上传方案就是form表单, 我们只需要在form内写好各种input(输入型元素), 并定义好上传的服务器地址(action)即可.形式类似如下:

<formaction="/xuxiaoxi/form/post"><divclass="form-item"><inputtype="text"/></div><divclass="form-item"><inputtype="passward"/></div><divclass="form-item"><inputtype="file"/></div><divclass="form-item"><inputtype="submit"/></div></form>

XHR技术还没普及时, 我们大多会选择上述方案, 唯一的缺点就是提交之后会刷新页面, 用户体验不太好, 还可能造成局部数据丢失, 但仍然有解决方案, 就是form + iframe技术.


1.1 form + iframe方案


form + iframe方案的基本思路就是我们提交动作是在父页面触发, 但是form表单指向为iframe, 这样可以实现局部刷新, 现在有些场景仍然在使用该方案, 具体原理如下:

网络异常,图片无法展示
|


以上两种方案都可以实现传统form提交下的局部刷新功能, 不过方案一需要单独维护iframe表单, 所以我呢一般采用方案二, 而且兼容性都可以达到IE9(虽然现在来说兼容IE浏览器意义不大, 但是还是要了解一下)


1.2 ajax + formData方案


XHR盛行之后,我们可以轻松使用ajax来实现异步请求了, 对于文件上传, 我们也可以更灵活的使用ajaxformData来实现, 逐渐脱离了对原生form表单的依赖.


FormData 对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据(keyed data),而独立于表单使用。如果表单enctype属性设为multipart/form-data ,则会使用表单的submit()方法来发送数据,从而,发送数据具有同样形式。


我们先来看一个简单的使用formData上传文件的例子:


letformData=newFormData();
// HTML 文件类型input,由用户选择formData.append("userfile", fileInputElement.files[0]);
letrequest=newXMLHttpRequest();
request.open("POST", "http://http://io.nainor.com/h5/form");
request.send(formData);

以上短短5行代码就实现了将文件通过formData的方式上传给了服务器, 是不是很简单呢? 笔者之前的文章 基于react/vue开发一个专属于程序员的朋友圈应用就采用了该方案, 感兴趣的可以学习研究一下.


如果要实现多文件上传也非常简单, 这里我们以axios为例, 具体实现如下:


constformData=newFormData()
for(leti=0; i<files.length; i++) {
formData.append(`file_${i+1}`, files[i].file)
}
axios({
method: 'post',
url: '/files/upload/tx',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'  }
});

这里要注意多文件上传要在请求的http header中设置 Content-Type 为  multipart/form-data . 当然大家还可以基于以上原理实现更符合自身业务需求的文件上传组件, 比如预览, 限流等.


1.3 第三方组件实现


为了更高效快速的开发业务, 我们有时候也可以选择第三方比较成熟的方案, 比如antd的upload组件, 比如element ui的上传组件, 这里笔者总结了几个比较好用且强大的方案, 大家可以感受一下:


  • antd/elementupload 组件
  • FilePond 可以上传任何内容,并能够优化图像以加快上传速度,同时提供顺畅的用户体验
  • Web Uploader  百度WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件
  • vue-simple-uploader 基于vue的强大美观的文件上传组件


我们可以通过上述提供的第三方组件库, 结合自己服务端的配置,就可以轻松实现强大的上传组件了.


2. 将裁剪功能集成到图片上传组件



对于图片上传组件来说, 我们往往不能确定用户上传的到底是什么, 所以我们要提前约束, 比如说对图片大小, 图片格式, 图片比例等进行限制以符合我们的业务标准. 图片大小和图片格式的限制非常好实现, 但是对于图片比例, 这个我们不能期望用户自己来处理, 因为这样会极大的增加用户使用网站的负担, 所以我们可以提供一种功能, 让用户在线切图. 如下图所示:


网络异常,图片无法展示
|


以上截图来自于H5-Dooring在线编辑器的图片上传组件, 在用户上传之后我们会出现图片裁切界面, 我们会指定图片的比例, 让用户自由裁切. 笔者将基于antdupload组件配合antd-img-crop来带大家实现在线切图功能. 具体代码实现如下:


importReact, { useState } from'react';
import { Upload } from'antd';
importImgCropfrom'antd-img-crop';
constDemo= () => {
const [fileList, setFileList] =useState([
    {
uid: '-1',
name: 'image.png',
status: 'done',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    },
  ]);
constonChange= ({ fileList: newFileList }) => {
setFileList(newFileList);
  };
constonPreview=asyncfile=> {
letsrc=file.url;
if (!src) {
src=awaitnewPromise(resolve=> {
constreader=newFileReader();
reader.readAsDataURL(file.originFileObj);
reader.onload= () =>resolve(reader.result);
      });
    }
constimage=newImage();
image.src=src;
constimgWindow=window.open(src);
imgWindow.document.write(image.outerHTML);
  };
return (
<ImgCroprotate><Uploadaction="https://www.mocky.io/v2/5cc8019d300000980a055e76"listType="picture-card"fileList={fileList}
onChange={onChange}
onPreview={onPreview}
>        {fileList.length<5&&'+ Upload'}
</Upload></ImgCrop>  );
};
ReactDOM.render(<Demo/>, mountNode);

以上只是一个基本的裁切并上传图片的例子, 当然antd-img-crop还提供了更多灵活的配置来方便我们设计更灵活强大的裁切效果. 当然我们还可以使用react-cropper来实现, 它提供了更灵活的裁切控制以及裁切实时预览功能, 如下图所示:


网络异常,图片无法展示
|



3. 内容平台/可视化平台下的图片自治



对于内容平台或者可视化平台而且, 单纯的上传图片还不能满足用户的需求, 因为内容/可视化平台更加注重图片的选择和使用, 对图片要求也很高, 用户自己上传毕竟资源有限, 往往不能达到用户对内容发布的需求或者可视化设计的需求, 所以往往在这类平台中会提供图片素材库这一功能, 用户可以在素材库中搜索海量图片以满足自己的需求, 而往往这样, 才更能留住用户, 增加用户粘性.


基于以上场景产品经理往往会提出这样的需求: 能不能提供可选方案, 用户既能自己上传图片, 也能使用我们提供的图片库资源呢? 这个时候有经验的前端往往会说一句: 安排!

在设计该功能之前我们往往要先参考其他已有实现, 这里我们举几个例子, 如下图所示:


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|



以上案例中我们可以发现在用户上传图片的时候都会提供两个可选选项, 一个是本地上传, 一个是直接在图片库中选择, 所以我们的方案也类似, 可以统一将图片库封装到文件上传组件中作为通用功能, 也可以组合式封装, 各自可以独立使用也可以组合使用.


对于H5-Dooring对图片库的封装, 使用了将其作为通用服务来实现, 也就是但凡使用了上传组件,一定会出现可选的从图片库选择按钮. 实现方案也很简单, 就是在upload组件中扩展一层, 使用Modal+Tab来做图片选择的界面, 当选择完成后将图片的地址手动设置到upload组件中即可. 代码如下:


handleImgSelected= () => {
constfileList= [
    {
uid: uuid(8, 16),
name: 'h5-dooring图片库',
status: 'done',
url: this.state.curSelectedImg,
    },
  ];
this.props.onChange&&this.props.onChange(fileList);
this.setState({ fileList, wallModalVisible: false });
};

这里用了antdform组件的受控模式.


4. 图片上传组件扩展



上面介绍的方案对于基本使用场景完全够用了, 但是如果是内容网站或者可视化搭建平台, 由于我们的配置可能会随时分发到公网, 这就会涉及到内容安全的问题, 如果一旦用户配置了违法的图片信息, 那么对于平台提供上可能会受到牵连, 所以我们还需要提供一套完善的审核机制, 比如用户配置好或者发布好内容后, 需要进过审核才能正式发布到线上, 但是完全依赖人工审核效率又比较低, 所以这个时候我们就需求找到机器自动化审核方案了. 比如阿里云和腾讯云等都提供了图片鉴别等服务, 我们可以将这些服务集成到我们的组件中, 来实现真正的业务自治能力, 这样才能更安全的进行企业化经营和开发.


还有一个需求就是用户对于上传的图片有编辑需求, 我们还可以提供对图片的在线编辑功能, 类似于如下方案:


网络异常,图片无法展示
|


我们能让用户有能力对自己选择的图片进行自行设计, 加水印等能力, 这样是不是更有意思呢?


5. 总结



以上教程笔者已经集成到H5-Dooring中,对于一些更复杂的交互功能,通过合理的设计也是可以实现的,大家可以自行探索研究。


github地址:H5在线编辑器H5-Dooring



目录
相关文章
|
云计算 运维 存储
aPaaS平台是什么?aPaaS与PaaS有什么区别?
aPaaS和PaaS都可以完成软件的开发和部署,都支持云端访问,而两者的差异主要体现在用户人群和使用环境不一样。
aPaaS平台是什么?aPaaS与PaaS有什么区别?
|
存储 供应链
flexsim仿真模型-MC公司下游仓库管理仿真实验(下)
flexsim仿真模型-MC公司下游仓库管理仿真实验
718 0
|
缓存 Java Spring
07HandlerMapping中用到的RequestMappingInfo和RequestCondition
RequestCondition(请求匹配条件)体系。 上面提到的RequestMapping注解申明的属性与之呼应的就是spring中RequestCondition的实现体系。 RequestMappingInfo体系 RequestMappingInfo是请求映射信息的描述,维护了一个请求所匹配的各种条件。即一个请求是有很多匹配条件的都放在了RequestMappingInfo中 RequestMappingInfo的生成、存放、和获取
1820 0
|
存储 关系型数据库 对象存储
体验云数据库RDS通用云盘核心能力
本次课程由杨浩磊(木信)分享,主题为体验云数据库RDS通用云盘的核心能力。内容分为四部分:1) 初识RDS通用云盘,介绍其低成本、高性能的特点;2) 核心能力详解,涵盖IO加速、IO突发和数据归档功能;3) 方案及应用案例,展示实际性能提升与成本优化;4) 线上活动与权益,提供免费试用等优惠。RDS通用云盘通过多级存储架构,显著提升读写性能并降低存储成本,适用于多种业务场景。
523 38
|
6月前
|
存储 JavaScript 安全
Web渗透-XSS漏洞深入及xss-labs靶场实战
XSS(跨站脚本攻击)是常见的Web安全漏洞,通过在网页中注入恶意脚本,窃取用户信息或执行非法操作。本文介绍其原理、分类(反射型、存储型、DOM型)、测试方法及xss-labs靶场实战案例,帮助理解与防御XSS攻击。
1884 1
Web渗透-XSS漏洞深入及xss-labs靶场实战
|
XML 前端开发 小程序
基于微信小程序+SpringBoot的停车位共享管理系统的设计和实现(一)
基于微信小程序+SpringBoot的停车位共享管理系统的设计和实现
818 0
基于微信小程序+SpringBoot的停车位共享管理系统的设计和实现(一)
|
存储 人工智能 弹性计算
通义万相AI绘画创作评测及图文搭建教程
【7月更文挑战第4天】阿里云的通义万相是AI绘画模型,结合ECS、OSS和API服务,提供无缝创作环境。用户上传图片至OSS,模型通过签名URL下载图片,然后生成AI艺术作品。模型服务具有高性能、易集成的特点,适用于多种场景如设计、广告等。用户可按指示在阿里云官网注册、充值、开通服务并部署。项目评测显示,其集成便捷、响应快、泛化能力强,但仍有改进空间,如增加图像控制选项和批量处理能力。相对于竞品,通义万相在成本、易用性和应用场景上有竞争力,值得推荐。
12410 9
|
自然语言处理 算法
ransformers从入门到精通:常用的subword tokenizer算法
- WordPiece、BPE/BBPE最小字词进行合并最终字词,BPE/BBPE直接采用词频判断合并规则而WordPiece采用最大似然的方式 - unigram采用从最大的字词集合里移除那些对语料库整体概率贡献最小的子词【6月更文挑战第7天】
508 3
|
机器学习/深度学习 人工智能 自然语言处理
|
消息中间件 编解码 Java
flink 写入Elasticsearch 踩坑小结
flink 写入Elasticsearch 踩坑小结