内容简介:最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子组件的交互功能要求如下:
最近工作一直在使用vue+vux做移动端项目,有一个拍照上传照片的需求,发现vux里并没有实现,调研过非官方的 vux-uploader 后,感觉还不是很理想。
其实网上已经可以找到很多已经实现的成熟方案,但是在调研这个需求的时候,我发现在各种实现方案中也有一些puzzle的知识点,因此自己动手撸了一个轮子 vux-uploader-component ,并记录一二。
需求
组件的交互功能要求如下:
- html5调用手机相机
- 渲染图片为缩略图
- 前端压缩图片
- 预览大图
- 删除当前图片
- 自动上传
部分关键技术点的实现方案
-
使用html media capture调用手机端的相机
<input type="file" accept="image/*" capture /> 复制代码
既然是在HTML5规范中,那最关心的问题肯定是兼容性了
可以看到,在大部分的主流平台,兼容性还可以接受,
andriod2-4 都支持,只是在ios6-10支持不太好。感兴趣的可以在自己的手机上测测兼容性
-
使用
ULR.createObjectURL获取图片地址blobURL = ULR.createObjectURL(object) 复制代码
object参数可以为
File、Blob、MediaSource在这一块可以衍生出好几个问题:
- 已知获取图片地址的方法有
URL.createObjectURL和FileReader.readAsDataURL,那应该使用哪个?为什么? - 在
IOS中拍照获取的图片会自动旋转,为什么?怎么解决? -
File和Blob是什么关系?Blob URL和Data URL又有什么区别?Data URL怎么转换成Blob?
- 已知获取图片地址的方法有
-
使用
canvas来压缩图片可以从两个方面可以进行压缩:
-
取一个最大宽度的限制对图片的宽高尺寸进行等比例的缩小
canvas.width = Math.min(image.naturalWidth, option.maxWidth) const ratio = canvas.width / image.naturalWidth canvas.height = image.naturalHeight * ratio 复制代码
-
canvas.toDataURL指定生成jpeg或者webp格式的图片,可以指定0-1之间的encoderOptionsdataURL = canvas.toDataURL("image/jpeg", encoderOptions) 复制代码
最后生成的图片大小 = 原图大小 *
ratio*encoderOption。 -
-
使用
FormData来上传const formData = new FormData() formData.append('file', blob) 复制代码这是
XHRLevel2的产物 ,可以方便的以键值对的形式插入。最大的优势是可以通过
XMLHttpRequest.send()来异步提交二进制文件。后期还可以通过
Blob的slice来扩展分片上传功能。
知识点剖析
FileReader和URL.createObjectURL的区别
关于 FileReader 和 URL.createObjectURL 的用法就不详细介绍了,感兴趣的自行google。
我们现在只需要知道
-
通过
FileReader.readAsDataURL(file)可以获取一段data:base64的字符串 -
通过
URL.createObjectURL(blob)可以获取当前文件的一个内存URL
既然这两个API都可以满足我们获取图片地址的需求,那它们之间的 区别 在哪呢?
1、执行时机
createObjectURL FileReader.readAsDataURL
2、内存使用
-
createObjectURL返回一段带hash的url,并且一直存储在内存中,直到document触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。 -
FileReader.readAsDataURL则返回包含很多字符的base64,并会比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)
3、兼容性
createObjectURL FileReader.readAsDataURL
从上面答案不难看出,两者的优劣势
- 使用
createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存 - 如果不太在意设备性能问题,并想获取图片的
base64,则推荐使用FileReader.readAsDataURL
参考
相机拍照的图片会旋转
从上面的 createObjectURL 获取到图片的地址后,我们可以插入到页面元素的 background-image 属性展示这个图片,PC端模拟器展示没有问题,但手机真机拍照得到的图片会有逆时针的90°旋转。
为什么从相机拍照获取的图片会旋转呢?
是因为从相机拍照获取的图片的EXIF(Exchangeable image file format)会默认设置一个 orientation tag
:point_up_2:上图就是 orientation tag 与图片旋转角度的对应关系
如何解决这个问题呢?
1、获取图片的 orientation
- 需要考虑兼容的话,建议使用 Exif.js
- 如果不希望有外部依赖,而且对兼容性要求不是那么高的话,可以利用
DataView来获取,详情见 stackoverflow高赞回答
2、根据图片的 orientation 做对应的旋转
switch (orientation) {
case 2:
// horizontal flip
ctx.translate(width, 0);
ctx.scale(-1, 1);
break;
case 3:
// 180 rotate left
ctx.translate(width, height);
ctx.rotate(Math.PI);
break;
case 4:
// vertical flip
ctx.translate(0, height);
ctx.scale(1, -1);
break;
case 5:
// vertical flip + 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.scale(1, -1);
break;
case 6:
// 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.translate(0, -height);
break;
case 7:
// horizontal flip + 90 rotate right
ctx.rotate(0.5 * Math.PI);
ctx.translate(width, -height);
ctx.scale(-1, 1);
break;
case 8:
// 90 rotate left
ctx.rotate(-0.5 * Math.PI);
ctx.translate(-width, 0);
break;
复制代码
参考
File和Blob的关系?Blob Url和DataURL的区别?DataURL如何转成Blob?
File和Blob的关系
从 input onchange 中返回的图片对象其实就是一个 File 对象。
而 Blob 对象是一个用来包装二进制文件的容器, File 继承于 Blob 。
FileReader 是用来读取内存中的文件的API,支持 File 和 Blob 两种格式。
Blob Url和Data URLs的区别
Blob Url 只能在浏览器中通过 URL.createObjectURL(blob) 创建,当不使用的时候,需要 URL.revokeObjectURL(blobURL) 来进行释放。
可以简单理解为对应浏览器内存文件中的软链接。该链接只能存在于浏览器单一实例或对应会话中(例如:页面的生命周期)
blobURL = URL.createObjectURL(blob) // blob:http://localhost:8000/xxxxxxxx 复制代码
Data URLs 可以获取文件的 base64 。
data:[<mediatype>][;base64],<data> 复制代码
mediatype 是个 MIME 类型的字符串,例如 " image/jpeg " 表示 JPEG 图像文件。如果被省略,则默认值为 text/plain;charset=US-ASCII
可以通过 FileReader.readAsDataURL 获取
const reader = new FileReader();
reader.addEventListener("load", e => {
const dataURL = e.target.result;
})
reader.readAsDataURL(blob);
复制代码
DataURL如何转成Blob?
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
// create a view into the buffer
var ia = new Uint8Array(ab);
// set the bytes of the buffer to the correct values
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ab], {type: mimeString});
return blob;
}
复制代码
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Build Your Own Web Site the Right Way Using HTML & CSS
Ian Lloyd / SitePoint / 2006-05-02 / USD 29.95
Build Your Own Website The Right Way Using HTML & CSS teaches web development from scratch, without assuming any previous knowledge of HTML, CSS or web development techniques. This book introduces you......一起来看看 《Build Your Own Web Site the Right Way Using HTML & CSS》 这本书的介绍吧!