首先技术选型
首先说说为什么要是用H5自带的原生API来写这个图片上传,因为笔者在这里找了好几天。因为公司项目临时要用,时间太赶,花了一天的时间并没找到一个比较好的demo让我转接,可能实力太差。: (
序言
开发微信中我遇到图片上传请求次数问题,腾讯那边调高了借口请求次数,每天200万次。最开始只有5000,项目早上上线下午就崩了,第二天100万下载50万请求次数,还是下午5点就崩了,第三天腾讯给调到200万了。实在没有办法,不想受制于腾讯,所以只能自己去研究能上传图片的方法了。
项目思路
我们都知道H5中有canvas这个API,不知道的小伙伴可以去Google一下看看。首先我们的思路是这样的,我们先拿到图片的base64的路径,然后用canvas画布技术在画出来。然后通过canvas API 提供的方法去压缩这样图片,然后上传,一样可以达到我们想要的效果。事情就是这么简单,但是这样的坑特别的多,谁写谁写知道。
开始实现
html 部分
# 申明一下,这里 accpet="image/*" 是为了识别出图片,所以这样写的
<body>
<input type="file" id="file_pic" name="image" accept="image/*" onchange="change_pic(event)">
</body>
JavaScript 部分
代码中我都标注过注释了,所以就不单独在拿出来直接写了,注释已经写的相当详细了。顺带说一句,过几天会更新微信端H5图片多张上传,以下是单张。: )
const imgInfo = {};
function change_pic(event) {
// 获取当前选中文件
const file = event.target.files[0];
// 设置图片最大尺寸
const imgMaxSize = 1024 * 1024 * 10;
// 检查文件类型
if (['jpeg', 'jpg', 'png', 'gif'].indexOf(file.type.split('/')[1]) < 0) {
// 自定义报错方式
console.log('图片格式不正确');
return;
}
// 图片大小超过限制
if (file.size > imgMaxSize) {
// 自定义报错方式
console.log('图片太大了');
return;
}
// 判断是否ios
if (!!window.navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
// 是 ios
insertFormData(file);
return;
}
// 开始图片压缩之旅
fileToDataUrl(file);
}
function insertFormData(file) {
// 新建form对象
const formData = new FormData();
// 自定义form对象中的内容
// type
formData.append('type', file.type);
// size
formData.append('size', file.size || "image/jpeg");
// name
formData.append('name', file.name);
// 最后修改时间
formData.append('lastModifiedDate', file.lastModifiedDate);
// 添加文件
formData.append('file', file);
console.log(file)
// 上传图片
// uploader(formData);
fileToDataUrl(file);
}
function fileToDataUrl(file) {
// 超过200k就压缩
const imgCompressMAX_SIZE = 200 * 1024;
// 组装相关文件数据
imgInfo.type = file.type || "image/jpeg"; // 部分安卓机使用不了
imgInfo.size = file.size;
imgInfo.name = file.name;
imgInfo.lastModifiedDate = file.lastModifiedDate;
// 使用filereader对象的函数
const reader = new FileReader();
// file 转换dataURL是一个异步函数,需要写在回调函数中
reader.onload = function (e) {
const result = e.target.result;
// 如果大于imgCompressMAX_SIZE 就压缩
result.length < imgCompressMAX_SIZE ? compress(result, false) : compress(result)
}
reader.readAsDataURL(file);
}
// canvas压缩图片
function compress(dataUrl, shouldCompress = true) {
const img = new window.Image();
img.src = dataUrl;
console.log(img.src.length)
img.onload = function () {
// 开始绘制图片
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 压缩过后图片的url
let compressedDataUrl;
shouldCompress = true ? compressedDataUrl = canvas.toDataURL(imgInfo.type, 0.2) : compressedDataUrl = canvas.toDataURL(
imgInfo.type, 0.2)
console.log(compressedDataUrl);
}
}
function uploader(formData) {
console.log(formData)
ajax({
method: 'post',
url: '',
data: formData,
success: function (resp) {
console.log(resp);
},
async: true
});
}
function createXHR() {
if (typeof XMLHttpRequest != 'undefined') {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != 'undefined') {
var version = [
'MSXML2.XMLHttp.6.0',
'MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp'
];
for (let i = 0; version.length; i++) {
try {
return new ActiveXObject(version[i]);
} catch (e) {
//跳过
}
}
} else {
throw new Error('您的系统或浏览器不支持XHR对象!');
}
}
//名值对转换为字符串
function params(data) {
let arr = [];
for (let i in data) {
arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(data[i]));
}
return arr.join('&');
}
// 封装ajax
function ajax(obj) {
let xhr = createXHR();
obj.url = obj.url + '?rand=' + Math.random();
obj.data = params(obj.data);
if (obj.method === 'get') obj.url += obj.url.indexOf('?') == -1 ? '?' + obj.data : '&' + obj.data;
if (obj.async === true) {
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
callback();
}
};
}
xhr.open(obj.method, obj.url, obj.async);
if (obj.method === 'post') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(obj.data);
} else {
xhr.send(null);
}
if (obj.async === false) {
callback();
}
function callback() {
if (xhr.status == 200) {
obj.success(xhr.responseText); //回调传递参数
} else {
console.log('获取数据错误!错误代号:' + xhr.status + ',错误信息:' + xhr.statusText);
}
}
}
// add event
function addEvent(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + type, function () {
fn.call(obj);
});
}
}
// remove event
function removeEvent(obj, type, fn) {
if (obj.removeEventListener) {
obj.removeEventListener(type, fn, false);
} else if (obj.detachEvent) {
obj.detachEvent('on' + type, fn);
}
}
PS 问题补充,上边代码只是单张上传,多张正在实现中,持续更新中!有帮助的话记得点个赞。
没办法,我也是临时遇到这个问题,完全没有想微信上传图片请求API是有次数制的,这是我之前没有遇到的过的,今天就记录下来,以便自己之后使用。我最终的结果就是把压缩过后的base64位的代码交给后台处理就好了。这样就实现了这个功能。
网友评论