工作中遇到的问题记录:vue开发头像上传组件,后端提供接口,需求为可相册上传,可相机拍摄上传,文件大小限制为2M

需求点分析

  1. 移动端调用相册/摄像头实现拍照
  2. 图片压缩,当前高像素的相机拍出来的图片都有个4-5m大小,超出了限定的2m
  3. 图片上传

第一点:移动端调用相册/摄像头实现拍照

这就比较简单了,H5的标签足已经能满足我们的要求了,我们要做的只是让它更美观一点

        <div class="yb-headSet-but">
<div class="btn-box">
<input type="file" accept="image/*" @change="uploadImg" class="fromAlbum"> //设置input opacity为0,定位覆盖a标签,a标签设置为设计稿的按钮样式
<a href="" class="weui-but">从相册选一张</a>
</div>
<div class="btn-box">
<a href="" class="weui-but">拍一张照片</a>
<input type="file" accept="image/*" @change="uploadImg" capture="camera" class="fromCamera"> //两者区别:capture="camera" 可直接调用摄像头
</div>
</div>

第二点:图片压缩

利用的是canvas的drawImage 和 toDataURL的api,具体代码是复制的 https://www.jianshu.com/p/4587312d2f44

修改了几个大佬笔误的地方

imgResize(file, callback) {
var _this = this;
var fileReader = new FileReader();
fileReader.onload = function() {
var IMG = new Image();
IMG.src = this.result;
IMG.onload = function() {
var w = this.naturalWidth,
h = this.naturalHeight,
resizeW = 0,
resizeH = 0;
// maxSize 是压缩的设置,设置图片的最大宽度和最大高度,等比缩放,level是报错的质量,数值越小质量越低
var maxSize = {
width: 500,
height: 500,
level: 0.6
};
if (w > maxSize.width || h > maxSize.height) {
var multiple = Math.max(w / maxSize.width, h / maxSize.height);
resizeW = w / multiple;
resizeH = h / multiple;
} else {
// 如果图片尺寸小于最大限制,则不压缩直接上传
return callback(file);
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
if (window.navigator.userAgent.indexOf("iPhone") > 0) {
canvas.width = resizeH;
canvas.height = resizeW;
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(IMG, 0, -resizeH, resizeW, resizeH);
} else {
canvas.width = resizeW;
canvas.height = resizeH;
ctx.drawImage(IMG, 0, 0, resizeW, resizeH);
}
var base64 = canvas.toDataURL("image/" + _this.fileType, maxSize.level);
_this.convertBlob(window.atob(base64.split(",")[1]), callback);
};
};
fileReader.readAsDataURL(file);
},

图片上传

使用canvas.toDataURL获得的是base64格式,上传时需要转换成Blob二进制格式,使用formData提交

//Blob对象生成
convertBlob(base64, callback) {
var buffer = new ArrayBuffer(base64.length);
var ubuffer = new Uint8Array(buffer);
for (var i = 0; i < base64.length; i++) {
ubuffer[i] = base64.charCodeAt(i);
}
var blob;
try {
blob = new Blob([buffer], { type: "image/" + this.fileType });
} catch (e) {
window.BlobBuilder =
window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if (e.name === "TypeError" && window.BlobBuilder) {
var blobBuilder = new BlobBuilder();
blobBuilder.append(buffer);
blob = blobBuilder.getBlob("image/" + this.fileType);
}
}
callback(blob);
},
//提交函数
postImg(file) {
let image = new FormData();
image.append("file", file, this.random_string(12) + '.' + this.fileType);
console.log(image);
setHead(image).then(res => {
this.$indicator.close();
if (res.Success) {
let newPath = res.photoPath +'?t=' + this.random_string(12);
this.$store.commit("UPDATE_BASEINFO", { photoPath: newPath });
this.picValue = newPath;
this.$messagebox.alert(res.Message);
} else {
this.$messagebox.alert(res.Message);
}
});
},

注意注意 这里有个巨大的坑。。。。。

这个坑是这样的,我使用压缩过的Blob格式提交后台时,返回提示文件格式不正确,不属于jpeg、jpg等,这我就纳闷了,我上传的formData里面写明了文件格式了啊;

后来经过简书大佬 一斤代码 老大的帮助,老大测试后说出了问题所在:那就是 FormData.append('file', file),如果只有两个参数,(第三个参数是文件名)的情况下,默认fileName=“blob”,这样上次至后台,如果后台未做其他处理的话,就会出现报错的情况,后来就添加了随机文件名,完整代码如下

<template>
<div class="yb-page">
<div class="yb-page-inner">
<div class="yb-headSetting">
<div class="yb-headSet-img">
<img :src="picValue" alt="" onerror="this.src='https://ixxxxxx.com/we/tmpls/t9000/img/account/blackHead@2x.png'">
</div>
<div class="yb-headSet-but">
<div class="btn-box">
<input type="file" ref="avatarInput" accept="image/*" @change="uploadImg" class="fromAlbum">
<a href="" class="weui-but">从相册选一张</a>
</div>
<div class="btn-box">
<a href="" class="weui-but">拍一张照片</a>
<input type="file" accept="image/*" @change="uploadImg" capture="camera" class="fromCamera">
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { setHead } from "@/api/user";
export default {
data() {
return {
picValue: this.$store.getters.baseInfo.photoPath,
file: null,
fileType: ''
};
},
methods: {
uploadImg(e) {
if (e.target.value == "") {
return;
}
this.$indicator.open();
let files = e.target.files || e.dataTransfer.files;
if (!files.length) return;
this.file = files[0];
this.fileType = this.file.type.split('/')[1];
this.imgResize(files[0], this.postImg);
},
postImg(file) {
let image = new FormData();
image.append("file", file, this.random_string(12) + '.' + this.fileType);
console.log(image);
setHead(image).then(res => {
this.$indicator.close();
if (res.Success) {
let newPath = res.photoPath +'?t=' + this.random_string(12);
this.$store.commit("UPDATE_BASEINFO", { photoPath: newPath });
this.picValue = newPath;
this.$messagebox.alert(res.Message);
} else {
this.$messagebox.alert(res.Message);
}
});
},
imgResize(file, callback) {
var _this = this;
var fileReader = new FileReader();
fileReader.onload = function() {
var IMG = new Image();
IMG.src = this.result;
IMG.onload = function() {
var w = this.naturalWidth,
h = this.naturalHeight,
resizeW = 0,
resizeH = 0;
// maxSize 是压缩的设置,设置图片的最大宽度和最大高度,等比缩放,level是报错的质量,数值越小质量越低
var maxSize = {
width: 500,
height: 500,
level: 0.6
};
if (w > maxSize.width || h > maxSize.height) {
var multiple = Math.max(w / maxSize.width, h / maxSize.height);
resizeW = w / multiple;
resizeH = h / multiple;
} else {
// 如果图片尺寸小于最大限制,则不压缩直接上传
return callback(file);
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
if (window.navigator.userAgent.indexOf("iPhone") > 0) {
canvas.width = resizeH;
canvas.height = resizeW;
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(IMG, 0, -resizeH, resizeW, resizeH);
} else {
canvas.width = resizeW;
canvas.height = resizeH;
ctx.drawImage(IMG, 0, 0, resizeW, resizeH);
}
var base64 = canvas.toDataURL("image/" + _this.fileType, maxSize.level);
_this.convertBlob(window.atob(base64.split(",")[1]), callback);
};
};
fileReader.readAsDataURL(file);
},
convertBlob(base64, callback) {
var buffer = new ArrayBuffer(base64.length);
var ubuffer = new Uint8Array(buffer);
for (var i = 0; i < base64.length; i++) {
ubuffer[i] = base64.charCodeAt(i);
}
var blob;
try {
blob = new Blob([buffer], { type: "image/" + this.fileType });
} catch (e) {
window.BlobBuilder =
window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if (e.name === "TypeError" && window.BlobBuilder) {
var blobBuilder = new BlobBuilder();
blobBuilder.append(buffer);
blob = blobBuilder.getBlob("image/" + this.fileType);
}
}
callback(blob);
},
random_string(len) {
len = len || 32;
var chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
var maxPos = chars.length;
var pwd = "";
for (var i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
}
};
</script>

vue头像上传与文件压缩的更多相关文章

  1. springboot整合vue实现上传下载文件

    https://blog.csdn.net/yhhyhhyhhyhh/article/details/89888953 文章目录 springboot整合vue实现上传下载文件 1上传下载文件api文 ...

  2. vue头像上传

    项目四知识点 默认头像 选择头像 <template> <div class="adatar"> <img :src="adatar?ada ...

  3. springboot 头像上传 文件流保存 文件流返回浏览器查看 区分操作系统 windows 7 or linux

    //我的会员中心 头像上传接口 /*windows 调试*/ @Value("${appImg.location}") private String winPathPic; /*l ...

  4. vue+element+upload实现头像上传

    后台 @RequestMapping("/up") public JSONObject up(@RequestParam("picFile") Multipar ...

  5. vue上传大文件控件

    文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹.今天研究了一下这个问题,在 ...

  6. AntDesign VUE:上传组件图片/视频宽高、文件大小、image/video/pdf文件类型等限制(Promise、Boolean)

    文件大小限制 - Promise checkFileSize(file, rules) { return new Promise((resolve, reject) => { file.size ...

  7. vue上传大文件的解决方案

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...

  8. 强大的flash头像上传插件(支持旋转、拖拽、剪裁、生成缩略图等)

    今天介绍的这款flash上传头像功能非常强大,支持php,asp,jsp,asp.net 调用 头像剪裁,预览组件插件. 本组件需要安装Flash Player后才可使用,请从http://dl.pc ...

  9. 【Bootstrap-插件使用】Jcrop+fileinput组合实现头像上传功能

    作者:Dreawer链接:https://zhuanlan.zhihu.com/p/24465742来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者:梦游的龙猫(转 ...

随机推荐

  1. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  2. C# winform或控制台Properties.Settings.Default的使用及存储位置

    C# winform或控制台Properties.Settings.Default的使用及存储位置 作者的程序 是MmPS.ClientForm.exe,使用Properties.Settings.D ...

  3. EL(表达式)语言的几种运算符

    1.EL的基本语法 (1)EL表达式语法:以${开头,以}结束,中间为合法的表达式,具体语法格式如下: ${expression} (2)参数说明:Expression:指定要输出的内容,可以是字符串 ...

  4. 重记解决kube-dns故障一则---ceph惹的祸

    上次,在同一个k8s集群里安装完ceph进行功能测试. 当测试完成之后,我停止了ceph的程序,再重新启动k8s集群. 结果,有一个应用就出问题了. 后来查出是因为防火墙里 Chain FORWARD ...

  5. 关闭webstorm自动保存,并显示文件未保存标识

    1.取消自动保存 2.显示编辑状态设置:

  6. js屏蔽手机的物理返回键

    $(document).ready(function() { if (window.history && window.history.pushState) { $(window).o ...

  7. bzoj 1854 并查集 + 贪心

    思路:这个题的并查集用的好NB啊, 我们把伤害看成图上的点,武器作为边,对于一个联通块来说, 如果是一棵大小为k的树,那么这个联通块里面有k - 1个伤害能被取到,如果图上有环那么k个值都能 取到,对 ...

  8. 【WPF】淡入淡出切换页面

    <NavigationWindow x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsof ...

  9. pycharm的安装教程及大坑

    在根据网上的教程创建新工程后,发现不能调用第三方库,网上大多给的是print('hello world'),己适python解释器用的pycharm默认的也不能发现错误.后来浏览了一篇文章才恍然大悟, ...

  10. 关于字体剥离和精简工具 FontSubsetGUI 和 FontPruner 的比较。

    在 Unity 中制作游戏时对动态字体的剥离和精简是现在常用的手段,现在有两篇博客是大家阅读和参照较多的,分别是 如何精简Unity中使用的字体文件 和 FontPruner 字体精简工具.他们各自提 ...