摘要:使用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. while循环--登录

    user = "fallen577" password = " count = 0 while count < 3: username = input(" ...

  2. 学号 20175223 《Java程序设计》第9周学习总结

    目录 教材学习内容总结 教材学习中的问题和解决过程 1. 输出文件时过多输出. 代码调试中的问题和解决过程 1. 问题:费马素性检验程序. [代码托管] 学习进度条 参考资料 目录 教材学习内容总结 ...

  3. WCF分布式4:客户端访问寄宿在IIS中的WCF服务

    部署过程比较简单,新建一个站点,指向服务的物理路径,设置一个端口.即可. 新建的站点对应一个应用程序池,设置应用程序池中的.NET版本为4.0 写一个测试客户端,访问IIS中的WCF服务,可能会出现, ...

  4. Maven可以使用mvn package指令对项目进行打包,如果使用Java -jar xxx.java

    Maven可以使用mvn package指令对项目进行打包,如果使用Java -jar xxx.jar执行运行jar文件,会出现"no main manifest attribute, in ...

  5. anaconda3下64位python和32位python共存

    查看当前工作平台:conda info 切换64位和32位: set CONDA_FORCE_32BIT=1是切换到32位 set CONDA_FORCE_32BIT= 是切换到64位 注意=号前后不 ...

  6. Python_02

    Python 判断语句  if,while if ture: print(1) else: print(0) for循环和内嵌函数range() range(a,b,c)   a:起始位置  b:终止 ...

  7. 2018-计算机系机试(第二批)-A-最大数

    单点时限: 1.0 sec 内存限制: 256 MB 输入 n 个整数,输出其中最大数的值. 例如:3 个整数 1 ,2 和 6 的最大值是 6 . 输入格式 每一行的第一个数是 n (1≤n≤20 ...

  8. 王者荣耀交流协会final发布-第3次scrum立会

    1.例会照片 成员高远博,冉华,王磊,王玉玲,任思佳,袁玥出席.拍照的是王磊同学,王超同学因参加比赛不在学校,不能出席. master:任思佳 2.时间跨度 2017年12月3日 18:00 — 18 ...

  9. 2019 Power BI最Top50面试题,助你面试脱颖而出系列<中>

    敲黑板啦!!! 来来来 大家双眼看黑板 开始划重点啦 这篇大部分是"考试"必考题 你们一定要好好的牢记在心 一分都不要放过 刷题中... Power BI面试题目-DAX 9)什么 ...

  10. 【EMV L2】Processing Restrictions

    目的: 处理限制(Processing Restrictions)的目的是确定终端中的应用程序与ICC中的应用程序的兼容程度,并进行任何必要的调整,包括可能拒绝交易. 执行条件: 终端应该都要执行Pr ...