图片拍照上传解决方案

前言

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

调用摄像头

 <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
张鑫旭

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

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