|
|
|
|
移动端

开发一个本地上传图片控件你需要知道的知识点

通过type为file的input标签选择本地图片上传,每次选择不同图片的时候会触发onChange事件。为什么我要强调不同图片,因为当两次选择的图片是一样的情况下,onChange事件无法触发。解决方法:每次处理完后手动置空input的value。

作者:佚名来源:稀土掘金|2018-01-10 11:06

【新品产上线啦】51CTO播客,随时随地,碎片化学习

接了一个「常规」需求:开发一个本地上传图片控件,需要支持三种上传方式:

  1. 支持打开本地目录,选择本地图片上传
  2. 支持拖曳图片上传
  3. 支持微信截图上传

我们先从工程角度来看一下用户上传图片的流程是怎样子的:

  1. 用户选择了一张本地图片,或者拖曳了一张图片,或者通过微信截图了一张图片。这时,我们需要知道用户所选择图片的信息,比如图片的内容、图片的大小、图片的类型等。
  2. 用户上传图片。这时,我们需要保存图片。
  3. 用户查看图片。这时,我们需要把第2步中保存的图片展示给用户。

如何获取到图片信息

通过input 打开本地目录,选择本地图片上传

通过type为file的input标签选择本地图片上传,每次选择不同图片的时候会触发onChange事件。为什么我要强调不同图片,因为当两次选择的图片是一样的情况下,onChange事件无法触发。解决方法:每次处理完后手动置空input的value。

  1. <input id='img-input' type='file' accept='image/*' onChange={this.bindChooseEvents} /> 
  1. // 置空input value 
  2.   clearImgInputValue () { 
  3.     document.getElementById('img-input').value = '' 
  4.   } 
  5.   bindChooseEvents = (e) => { 
  6.     console.log('choose a image'
  7.  
  8.     // 获取File对象 
  9.     const file = e.target.files[0] 
  10.     let size = file.size 
  11.  
  12.     if (!file.type.match('image.*')) { 
  13.       AntMessage.warning('File\'s type is not supported. Images only.'
  14.       this.clearImgInputValue() 
  15.       return
  16.     } 
  17.  
  18.     if (size > maxSize) { 
  19.       AntMessage.warning('The size of the image is too large'
  20.       this.clearImgInputValue() 
  21.       return
  22.     } 
  23.  
  24.     /* eslint-disable */ 
  25.     const reader = new FileReader()  // FileReader 
  26.     /* eslint-disable */ 
  27.     // 将图片转换为base64 
  28.     reader.readAsDataURL(file) 
  29.     reader.onload = (arg) => { 
  30.       // 获取到base64图片内容 
  31.       const fileStream = arg.target.result 
  32.       /** 
  33.        * overwrite do something 
  34.        * */ 
  35.       this.clearImgInputValue() 
  36.     } 
  37.   } 

拖曳图片上传

监听拖曳事件,通过拖曳相关的DataTransfer对象获取图片信息。

  1. <div id='drop-zone' style={{width: '100px', height: '100px'}}>Drop Zone</div> 
  2. bindDragEvents = (e) => { 
  3.     const handleDragOver = (event) => { 
  4.       event.stopPropagation() 
  5.       event.preventDefault() 
  6.       event.dataTransfer.dropEffect = 'copy' 
  7.     } 
  8.  
  9.     // 必须阻止dragenter和dragover事件的默认行为,这样才能触发 drop 事件 
  10.     const handleFileSelect = (event) => { 
  11.       event.stopPropagation() 
  12.       event.preventDefault() 
  13.  
  14.       const files = event.dataTransfer.files // 文件对象 
  15.       const file = files[0] 
  16.       const size = file.size 
  17.       const type = file.type 
  18.  
  19.       if (!type.match('image.*')) { 
  20.         AntMessage.warning('File\'s type is not supported. Images only.'
  21.         return
  22.       } 
  23.  
  24.       if (size > maxSize) { 
  25.         AntMessage.warning('The size of the image is too large'
  26.         return
  27.       } 
  28.  
  29.       /* eslint-disable */ 
  30.       const reader = new FileReader() 
  31.       /* eslint-disable */ 
  32.       // 将图片转换为base64 
  33.       reader.readAsDataURL(file) 
  34.       reader.onload = (arg) => { 
  35.         // 获取到base64图片内容 
  36.         const fileStream = arg.target.result 
  37.         /** 
  38.          * overwrite do something 
  39.          * */ 
  40.       } 
  41.     } 
  42.  
  43.     const dropZone = document.getElementById('drop-zone'); 
  44.     dropZone.addEventListener('dragover', handleDragOver, false); 
  45.     dropZone.addEventListener('drop', handleFileSelect, false); 
  46.   } 

微信截图上传

监听paste事件,通过剪贴板对象clipboardData获取图片信息。

  1. bindClipEvents() { 
  2.     document.addEventListener('paste', (e) => { 
  3.       console.log('paste a image'
  4.       const clipboard = e.clipboardData 
  5.  
  6.       // 有无内容 
  7.       if (!clipboard.items || !clipboard.items.length) { 
  8.         AntMessage.warning('No content in the clipboard'
  9.         return
  10.       } 
  11.  
  12.       let item = clipboard.items[0] 
  13.       if (item.kind === 'file' && item.type.match('image.*')) { 
  14.           // 获取图片文件 
  15.           let imgFile = item.getAsFile() 
  16.  
  17.           if (imgFile.size > maxSize) { 
  18.             AntMessage.warning('The size of the image is too large'
  19.             return
  20.           } 
  21.  
  22.           const reader = new FileReader() 
  23.           // 将图片转换为base64 
  24.           reader.readAsDataURL(imgFile) 
  25.           reader.onload = (arg) => { 
  26.             // 获取到base64图片内容 
  27.             const fileStream = arg.target.result 
  28.             /** 
  29.              * overwrite do something 
  30.              * */ 
  31.           } 
  32.       } else { 
  33.         AntMessage.warning('File\'s type is not supported. Images only.'
  34.       } 
  35.     }, false
  36.   } 

如何保存

图片保存一般都采用独立图片独立域名服务器,不会傻乎乎地把图片保存在web服务器上也不会直接存在项目表的数据库中。这样做有什么好处呢?

  1. 图片访问是I/O密集型操作,很消耗服务器资源,从Web服务器独立出来后,能够减少Web服务器压力
  2. 便于扩容、容灾和数据迁移
  3. 浏览器有同域名下的并发策略限制
  4. 请求图片一般并不需要cookie,但是浏览器发起的所有同域名请求时,http头部都会自动带上cookie信息,导致浪费带宽
  5. 方便对图片访问做负载均衡,可以对图片应用各种缓存策略
  6. 方便迁移CDN ...

总结&优化

流程图:

不足:

项目实践中我们虽然采用了独立图片服务器,下载过程只是通过Web服务器去数据库拿到图片地址,但是我们的上传操作仍旧经过了Web服务器,需要Web服务器上的应用程序来处理,所以上传过程仍旧对Web服务器造成压力。所幸的是,我们对图片上传大小进行了1M的大小限制,同时作为内部系统没啥访问压力,而且图片上传功能也并不是很高发的行为,所以这么做基本也不会有啥问题。但是最好的方案还是不管下载上传都直接走独立图片服务器,避免对Web服务器造成额外的压力。

【编辑推荐】

  1. 有了记忆才能发挥出服务器的威力,python架服务器连接数据库速成
  2. 服务器为什么要做磁盘阵列?
  3. 服务器Bug导致腾讯视频会员0.2元/月遭疯抢!官方全部兑现
  4. 2018值得选用的五个Linux服务器发行版
  5. Linux如何判断自己的服务器是否被入侵
【责任编辑:武晓燕 TEL:(010)68476606】


点赞 0
分享:
大家都在看
猜你喜欢

视频课程+更多

热门职位+更多

读 书 +更多

网络管理员备考训练——计算机与网络基础知识

本书是根据全国计算机技术与软件专业技术资格(水平)考试《网络管理员考试大纲》所要求的考试范围而编写的试题集。全书共分10个单元,同步...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊