摘要:使用HTML5编写移动Web应用,主要是为了尝试一下“一套代码多处运行”,一个webapp几乎可以不加修改的运行在PC/Android/iOS等上面运行。但是写到现在觉得虽然这种方式弊大于利,不仅在速度上有差异,webapp对移动端的一些原生功能支持并没有那么好。我用的vue写的系统,完成之后用webpack打包模块,hbuilder打包成apk,但是要解决的问题并不少。现在来说说webapp拍照上传。

html5是支持拍照上传或者调用本地相册的,

<!--兼容安卓微信调用摄像头-->
<input type="file" name="file" capture="camera"> <!--兼容安卓默认选择sd卡上的相册图片-->
<input type="file" name="file" accept="image/*" >

然而hbuilder打包apk之后,在安卓机(华为荣耀9)测试的时候,发现  capture="camera" 失效了,打开的是本地相册,但是不能调用摄像头。我就打开了webpack-server,移动端的浏览器运行的时候,在浏览器里面是可以调用摄像头的,最后发现了很多人都有这个问题,但是并没有说明解决办法。我自己最后是结合H5提供的 window.plus 功能调用移动端的摄像头,当然,先判断移动端是否支持 window.plus ,如果不支持,就依然用 <input> 实现图片选取。

H5 的 plus.camera 官方 API:http://www.html5plus.org/doc/zh_cn/camera.html

下面我就说说我的解决方法,主要是参照了网上一些实例和官网API写出来的,请看下面的VUE组件,这个组件可以直接引用,有兴趣的同学可以试试:

 <template>
<div>
<div class="camera-photo" ref="divGenres" v-show="isPhoto" @click="choiceImg">
<img style="width:300px;height:300px;" src="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1528077222&di=69a2ffcffd12e35216ab71da7a610abe&src=http://img.zcool.cn/community/01f15555b4df7e6ac725ca50c172a1.png@2o.png"/>
<br>
<span>请选择图片上传</span>
<input type="file" ref="uploadImage" @change="onFileChange" accept="image/*" capture="camera" style="display: none;">
</div> <div class="list-li" v-show="show">
<div style="display: inline-block;">
<a class="list-link" @click='previewImage(imgsrc)'>
<img :src="imgsrc">
</a>
<span class="list-img-close" @click='delImage'></span>
</div>
<div class="add-preview" v-show="isPreview" @click="closePreview">
<img :src="previewImg">
</div>
<button type="button" class="upload-button" @click="upload">图片上传</button>
</div>
</div>
</template> <script>
import Bus from '../bus.js'
import qs from "qs"
export default {
data(){
return{
imgsrc:'',//上传的·图片的地址
show:false,//图片放大预览
previewImg: '',//预览图片的地址
isPreview: false,//是否预览当前图片
isPhoto: true,
uploadFile:null
}
},
methods:{ choiceImg(){
let self = this;
if (!window.plus){
self.addPic()//如果不支持plus,就用本地相册上传即可
return;
} let title = "选择照片"
let btns = ['拍照','相册'] var func = function(e){
var index = e.index; if(index == 1) self.choiceCamera();
if(index == 2) self.choicePic();
} if(title && btns && btns.length > 0){
var btnArray = [];
for(var i=0; i<btns.length; i++){
btnArray.push({title:btns[i]});
} plus.nativeUI.actionSheet({
title : title,
cancel : '取消',
buttons : btnArray
}, function(e){
if(func) func(e);
});
}
}, choiceCamera(){
let self = this;
var cmr = plus.camera.getCamera();
cmr.captureImage(function (path){ plus.io.resolveLocalFileSystemURL(path, function(entry){
self.imgsrc= entry.toLocalURL();
self.show = true; }, function(e){plus.nativeUI.toast("读取拍照文件错误:" + e.message); });
}, function(e){},{index:1,filename:"_doc/camera/"});
} , choicePic(){
let self = this;
plus.gallery.pick( function(p){
plus.io.resolveLocalFileSystemURL(p, function(entry) {
self.imgsrc= entry.toLocalURL();
self.show = true;
}, function(e) {
plus.nativeUI.toast("读取拍照文件错误:" + e.message);
});
}, function ( e ) { plus.nativeUI.toast("读取拍照文件错误:" + e.message);}, {
filename: "_doc/camera/",
filter:"image"
} );
}, upload(){
var self = this
var wt ;
if (window.plus)
wt = plus.nativeUI.showWaiting(); var img = new Image,
width = 512, //image resize 压缩后的宽
quality = 0.5, //image quality 压缩质量
canvas = document.createElement("canvas"),
drawer = canvas.getContext("2d");
img.src = self.imgsrc;
img.onload = function(){//利用canvas压缩图片
canvas.width = width;
canvas.height = width * (img.height / img.width);
drawer.drawImage(img, 0, 0, canvas.width, canvas.height);
var base64 = canvas.toDataURL("image/*", quality);
var pic = base64.split(',')[1];//图片的base64编码内容
var f=self.imgsrc;
var filename=f.replace(f.substring(0, f.lastIndexOf('/') + 1), '');//图片名称 if(self.uploadFile !== null){//addPic方法得到的图片文件
filename = self.uploadFile.name
let reader = new FileReader();
reader.readAsDataURL(self.uploadFile);
reader.onload = function(e){
img.src = e.target.result;
}
img.onload = function(){
canvas.width = width;
canvas.height = width * (img.height / img.width);
drawer.drawImage(img, 0, 0, canvas.width, canvas.height);
base64 = canvas.toDataURL("image/*", quality);
pic = base64.split(',')[1];
}
}
      //此处是将图片上传到服务器的代码,略过
}
}, onFileChange(e){
let self = this;
let files = e.target.files || e.dataTransfer.files;
if (!files.length) return;
let file = files[0];//File对象
self.uploadFile = file;
let reader = new FileReader();//FileReader对象
reader.readAsDataURL(file);//该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。 reader.onload = function(e){
self.imgsrc= e.target.result;//图片内容的base64编码
self.show = true;
}
}, addPic: function (e) {
let els = this.$refs.divGenres.querySelectorAll('input[type=file]')
els[0].click()
return false
}, delImage: function () {
this.imgsrc = "";
this.show = false;
this.isPreview = false;
}, previewImage: function (url) {
let vm = this;
vm.isPreview = true;
vm.previewImg = url;
}, closePreview: function () {
let vm = this;
vm.isPreview = false;
vm.previewImg = "";
},
},
}
</script> <style>
.upload-button{
display: block;
margin-top: 10px;
}
.camera-photo{
text-align:center;
margin-top:80px;
}
.list-li { display: flex;
flex-direction: column;
align-items: center;
padding: 8px;
margin-top:10px;
position: relative;
text-align: center;
margin-left: auto;
margin-right: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.list-link img {
width: 150px;
height: 150px;
}
.list-link a:visited {
background-color: #465c71;
border: 1px #4e667d solid;
color: #dde4ec;
display: flex;
line-height: 1.35em;
padding: 4px 20px;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
}
.list-link a:hover {
background-color: #bfcbd6;
color: #465c71;/
text-decoration: none;
}
.list-link a:active {
background-color: #465c71;
color: #cfdbe6;
text-decoration: none;
}
.list-img-close {
background: #ffffff url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1526905315674&di=4c2d6a6985b34e141f37bc9fae7f2209&imgtype=0&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F15%2F55%2F73%2F39I58PICCqK_1024.png) no-repeat right top;
border-color: #ff4a00;
background-position: center;
background-size: 35px 35px;
display: block;
float: left;
top: 5px;
width: 10px;
height: 10px;
position: absolute;
margin-top: 0px;
margin-left: 135px;
padding: 8px;
z-index: 10;
border-radius: 5px;
text-align: center;
}
.add-preview{
width: 300px;
height: 300px;
}
.add-preview img{
width: 100%;
height: 100%;
}
</style>

总之,尝试之后觉得,web工程师如果要做移动端开发,还是得有安卓或者ios工程师的支持。

补充:2018-8-24

  canvas的图片压缩原理,canvas可以改变图片大小,也可以改变图片质量。quality改变图片质量。base64只是对图片对应的二进制码,按照六位对应一个字符规则做转换,转码后是反而比原图片文件大的。但是对于小图片而言,经转换后多出来的字节传输远比多建立一个http连接开销小,所以会利用base64对小图转码来提高页面加载速度。至于图片压缩原理,简单来说,通过算法减少一张图片上的颜色差异,牺牲图片画质。比如紧挨着的颜色相近的四个像素的颜色信息压缩前大概占16个字节,压缩后变成一个颜色就能减少近4倍。quality用来控制色差的力度,值越小力度越大,颜色相差较大的两个像素也会被处理,自然被压缩后文件就越小,画质就越烂。

用base64编码,源文件会变大,base64不能压缩图片,base64就是为了减少http请求。

webAPP如何实现移动端拍照上传(Vue组件示例)?的更多相关文章

  1. 附件上传vue组件封装(一)

    //父页面部分 <attachment @newFileList="newFileList" :operationType="operationType" ...

  2. iOS拍照上传后,在web端显示旋转 Swift+OC版解决方案

    问题描述: 手机头像上传,遇到一个怪现象,就是拍照上传时,手机端显示头像正常,但在web端查看会有一个左旋90度的问题. 并且照片竖怕才会有此问题,横拍不存在. 原因分析: 手机拍照时,用相机拍摄出来 ...

  3. Android4.4 + WebAPI 实现拍照上传

    网上有很多关于拍照上传的实现方法,如果用新版本android去运行有可能会发现根本实现不了.主要原因是android从4.4版本开始通过intent.ACTION_GET_CONTENT打开选择器后, ...

  4. php实现手机拍照上传头像功能

    现在手机拍照很火,那么如何使用手机拍照并上传头像呢?原因很简单,就是数据传递,首先手机传递照片信息,这个就不是post传递 也不是get函数传递, 这个另外一种数据格式传递,使用的是$GLOBALS ...

  5. php实现视频拍照上传头像功能实例代码

    如果要在php中实现视频拍照我们需要借助于flash插件了,由flash拍出的确照片我们再通过php的$GLOBALS ['HTTP_RAW_POST_DATA']接受数据,然后保存成图片就可以了,下 ...

  6. 移动端图片上传解决方案localResizeIMG先压缩后ajax无刷新上传

    现在科技太发达,移动设备像素越来越高,随便一张照片2M+,但是要做移动端图片上传和pc上略有不同,移动端你不能去限制图片大小,让用户先处理图片再上传,这样不现实.所以理解的解决方案就是在上传先进行图片 ...

  7. html5调用手机摄像头,实现拍照上传功能

    今天做手机网站,想实现手机扫描二维码功能.首先实现在浏览器中调用手机摄像头,实现拍照功能并且把拍下的照片显示在页面并上传到服务器上,然后再在服务器端进行分析. 首先实现在浏览器中调用摄像头,当然用现在 ...

  8. 【Demo】HTML5 拍照上传

    本文主要讲解 手机浏览器 如何拍照 为什么会有这个需求 最近做一个项目要用到拍照然后上传照片,但是网页拍照一般都是用Flash做的,而我们主要是H5页面,如果在微信里面有权限就可以通过JSSDK调起摄 ...

  9. Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

随机推荐

  1. vim里添加自动补齐插件,与python 函数补齐

    参考  http://www.jb51.net/article/58009.htm 将 # cat ~/.vimrc filetype plugin on let g:pydiction_locati ...

  2. [转载] java并发编程:Lock(线程锁)

    作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...

  3. 浏览器兼容性汇总--CSS篇

    目录 CSS篇 1.       cursor:hand   VS   cursor:pointer 2.        innerText在IE中能正常工作,但在FireFox中却不行 3.     ...

  4. ES6 let&const

    今天来总结一下ES6里面let与const的用法 先总体看一下ES6中的let都有哪些特性: let 特性 let声明的变量在js中不可以重复声明,防止变量的污染和覆盖 let声明的变量不涉及变量的提 ...

  5. 今天写代码遇到了一个BUG

    在我们日常写注释是需要注意,在有返回值的里面不要用以下方式注释,不然不会报错,运行状态码返回也是200,但就不是想要的结果. 下面举个例子 return { 'token':token, 'user_ ...

  6. 在VS中连接MySQL

    VS没有主动提供那些繁多的连接器,需要的话得自己再安装这些第三方程序包. MySQL为windows平台开发者提供了许多程序包:http://dev.mysql.com/downloads/windo ...

  7. 【oracle】dmp导数据库

    假定数据库A为源数据库,数据库B为目标数据库 step1在数据库A中,导出生成.dmp文件,操作流程如下(以下操作均在系统用户ora11g下执行) 1.该操作只需要在第一次使用时执行,A_dump_d ...

  8. Vue.js devtool插件安装后无法使用的解决办法【最简单有效的解决方法】

    在开发vue相关的项目时,使用vue devtools工具是一件极其有趣的事,你所有的操作都马上给你实时反馈. 然而有时候安装好的工具,在chrome中不显示. 在网上找过多次,一直没有找到有效解决方 ...

  9. myEclipse出现cannot paste the clipboard contents into the selected elements报错

    导入jar包报错,cannot paste the clipboard contents into the selected elements,查阅资料让重新打开工程,但依然报错. 最后在本地路径复制 ...

  10. 整合spring+springmvc+mybatis

    开发环境: jdk 1.8 eclipse 4.7.0 (Oxygen) tomcat 8.5.29 mysql 5.7 开发前准备: spring 框架的jar包,在这里使用的是spring-5.0 ...