图片拍照上传解决方案

前言

图片上传是常见的需求之一,本文讲解自己的解决过程,以及遇到坑。

调用摄像头

 <input type="file" accept="image/*" capture name="" value="">

微信内置浏览器,和一些主流浏览器支持调用摄像头,但也有很多不支持调用摄像头,仅支持相册。
如果是WebView中,就需要客户端支持了,android和ios的权限也是问题。

formData方式

formData简介

简单的说就是:通过formData,我们可以用ajax方式来发送表单数据;以前上传图片是需要用form表单提交的。

界面部分

我们知道浏览器默认显示的文件上传按钮是很丑的,通常UI都会对上传按钮进行设计。有以下几种方案来写样式。

  • 方案一
    外部写设计样式,内部写上传按钮,并设置上传按钮的透明度。
<div class="upload-wrapper">
      upload
      <input type="file" name="upload" multiple="multiple" accept="image/*" value="">
    </div>
.upload-wrapper {
  position: relative;
  box-sizing: border-box;
  overflow: hidden;
  width: 100px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  border-radius: 5px;
  border: 1px solid pink;
  background: #fff;
}
.upload-wrapper:hover {
  background: pink;
  color: #fff;
}
input[type="file"] {
  box-sizing: border-box;
  opacity: 0;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}
upload-1.png

弊端:

  • 样式复杂,涉及定位
  • cursor设置pointer无效
    • 为保证点击上传按钮时,文件窗口弹出,这里是通过事件冒泡起作用的。
    • 真正的input type="file"由两部分组成,左边的按钮,右边的提示部分;实际上当鼠标在左边的按钮上时,cursor不起作用
  • 总会提示title "未选择任何文件"
upload-2.png
  • 方案二
    input type="file"隐藏,当点击外部容器时,模拟点击上传按钮。

  • 在pc端模拟点击暂时没有发现异常
  • 在移动端模拟点击会出现两个问题
    • 事件冒泡
      点击外部容器 --> 触发模拟点击上传按钮 --> 触发事件冒泡 --> 点击外部容器,导致两个事件递归了。
    • 触发无效
      当阻止冒泡事件后,确实触发了点击,log不会打印出来,文件窗口不会弹出来;此时切换到pc,发现log打印出来,并且之前的log也打印出来了,文件窗口弹出。
 <div class="upload-wrapper" @click="upload('logo_path')">
      upload
      <input ref="logo_path" type="file" name="logo_path" multiple="multiple" accept="image/*" value="" @change="selectImg('logo_path')">
    </div>
  .upload-wrapper {
  box-sizing: border-box;
  overflow: hidden;
  width: 100px;
  height: 40px;
  line-height: 40px;
  text-align: center;
  border-radius: 5px;
  border: 1px solid pink;
  background: #fff;
  cursor: pointer;
}
.upload-wrapper:hover {
  background: pink;
  color: #fff;
}
/* pc端 */
input[type="file"] {
  display: none;
}
/* 移动端 */
input[type="file"] {
  width: 0;
  height: 0;
  z-index: -1;
}

通过ref获取上传按钮。

/**
* 触发上传
*/
upload: function (name) {
  this.$refs[name].click()   // 触发了selectImg函数
},

上传过程

selectImg: function (name) {
    // 获取文件
    ...
    // 校验
    ...
    // formData
    ...
}
获取文件

ref方式

   let file = this.$refs[name].files[0]

event.target方式

 /**
   * 获取图片
   */
  function getImg (files) {
    var file;
    if (files && files.length > 0) {
      file = files[0];
    }
    return file;
  }
校验
function verifyImg(file) {
  // 空
  if (!file) {
    return false
  }
  // 图片格式
  if (!/\/(?:jpeg|png|jpg|bmp)/i.test(file.type)) {
      // 提示操作
       return false
   }
  // 图片大小
   if (file.size > 5 * 1024 * 1024) {
        // 提示操作
       return false
   }
}
formData

坑:

  • formData.append(key, value)
    key的设置要和后端沟通好。
  • 使用axios的时候,不需要设置contentType
    我设置multipart/form-data,反而不行,谨记!!!
let formData = new FormData()
formData.append('UploadForm[image]', file)
let that = this
axios.post(url, formData)
     .then(function (res) {
     // success
   })
   .catch(function (error) {
       console.log(error)
   })

图片预览

FileReader

FileReader简介

通过readAsDataURL(),在读取操作完成后,result属性中将包含一个data:URL格式的字符串以表示所读取文件的内容。

if (window.FileReader) {
    let fr = new FileReader()
    let that = this
    fr.readAsDataURL(file)
    fr.onloadend = function (e) {
       that.imgUrl = e.target.result
    }
 }

base64字符串

    /**
     * 将图片转化成base64字符串,并上传
     */
    function base64(file) {
      if (window.FileReader) {
        var fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onloadend = function (e) {
          var params = e.target.result;
          // 以下是去掉data协议
          // params = params.replace("data:image/jpeg;base64,", "") 
        }
      }
    }

兼容性

我在safari中测试,发现是支持的。

support.png
URL.createObjectURL()

URL.createObjectURL简介

通过URL.createObjectURL()创建一个URL对象,这个URL对象表示指定的file对象或Blob对象。

this.imgUrl = window.URL.createObjectURL(file)

兼容性

support.png

canvas压缩图片

张鑫旭的文章:HTML5 file API加canvas实现图片前端JS压缩并上传

数据类型

张鑫旭的文章:理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型

参考

使用Camera API
张鑫旭

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,841评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,908评论 25 708
  • 我独来独往,天生傲娇,带着丰富多彩的内心世界遗失孤立般的生活在霓虹喧嚣的大城市。 我一直喜欢一个人。即使多一个他,...
    林四月阅读 535评论 6 10
  • 请原谅老师一直到现在才给你回信! 首先,老师要告诉你,你一直是老师心中的好孩子,你依然是老师眼中的“日...
    小肥皂sy阅读 796评论 0 3
  • 来三亚的时间不长也不短,刚好三个月了。这是我毕业离开学校后的三个月,也是我们创业的第三个月。不论一个能力有限、刚刚...
    柒壹阅读 486评论 0 3