小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
H5 图片上传组件:可单独使用,也可以嵌入 android 原生壳子中,与手机端进行交互使用。基于 input 进行组件封装,完成权限问题、图片上传、图片压缩、图片 转 base64 格式,base64 转 Blob 等
- 权限问题:相机+存储双权限,相机拍照,相册获取
- 图片上传:可批量上传,同时传多张图片
- 图片压缩:使用 canvas 压缩处理
- 图片预览:图片数据转为 base64 格式
- 重复图片无法上传(清除 input 的值)
组件封装
<template>
<div @click.stop="chooseType" class="upload-wrap">
<slot name="upload">
<div class="upload-item">
<img src="/images/icon_upload.png" class="item-img" />
</div>
</slot>
<input
id="uploadIcon"
ref="uploadIcon"
@change="uploadImg($event)"
type="file"
accept="image/*"
style="display: none;"
capture="camera"
/>
</div>
</template>
<script>
export default {
name: "UploadImage",
props: {
quality: {
// 图片质量
type: Number,
default: null,
},
width: {
// 图片宽度
type: Number,
default: null,
},
height: {
// 图片高度
type: Number,
default: null,
},
},
data() {
return {
picList: [],
};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.upload-wrap {
.upload-item {
width: 1.68rem;
height: 1.68rem;
border-radius: 0.12rem;
margin-right: 0.2rem;
position: relative;
overflow: hidden;
.item-img {
width: 100%;
height: 100%;
}
}
}
</style>
复制代码
权限问题
需要与客户端进行交互,获取权限。我们这边的权限参数是客户端挂载在 window 上的
export default {
computed: {
isApp() {
return this.$store.state.nativePara.isApp;
},
},
methods: {
// 点击之后,首先进行权限判断
chooseType() {
// 客户端交互 获取权限
if (this.getPermession()) {
// 通过校验后,主动触发 input 的 click 事件
document.getElementById("uploadIcon").click();
}
},
getPermession() {
// 如果是在app中
if (this.isApp) {
// 获取照相机权限
const permission = window.xxx.checkPermission(
"android.permission.CAMERA"
);
if (permission === 0) {
// 没开的话,申请开启
window.xxx.requestPermission("android.permission.CAMERA");
return false;
}
// 本地存储权限
const permission2 = window.xxx.checkPermission(
"android.permission.WRITE_EXTERNAL_STORAGE"
);
if (permission2 === 0) {
// 没开的话,申请开启
window.xxx.requestPermission(
"android.permission.WRITE_EXTERNAL_STORAGE"
);
return false;
}
}
return true;
},
},
};
复制代码
图片上传
- 检查:检查文件是否被选中;文件是否过大;文件类型是否正确
- 处理:图片压缩,base64 转化
export default {
methods: {
uploadImg(e) {
// 检查是否有文件被选中
const files = e.target.files || e.dataTransfer.files;
if (!files.length) {
return;
}
// 检查文件是否过大
const file = files[0];
if (file.size / 1024 > 5000) {
this.$toast.show("图片太呀,请压缩后再上传", {
duration: 3000,
});
return;
}
// 判断文件类型:必须是图片才处理
if (!/^image\//.test(file.type)) {
this.$toast.show("请上传图片", { duration: 3000 });
// 不是图片的话,清除数据
document.getElementById("uploadIcon").value = "";
return;
}
this.convertBase64(file, (blob) => {
const data = this.compress(blob); // 压缩照片
console.log('压缩后的图片大小',data.length)
const imageData = {
time: new Date().getTime(),
uri: data,
};
this.$emit("on-upload", imageData);
});
},
},
};
复制代码
图片预览
图片预览:将图片数据转为 base64 格式,返回给使用者
- FileReader.readAsDataURL(file)获取 data:base64 的字符串。同步执行(立即)
- URL.createObjectURL(blob)获取当前文件的一个内存 URL,表示指定的 File 对象或 Blob 对象。异步执行(需要时间)
export default {
methods: {
convertBase64(file, callback) {
// 判断是否支持FileReader
if (!window.FileReader) {
const URL = window.URL || window.webkitURL;
const blob = URL.createObjectURL(file); // 获取照片的文件流
if (callback) {
callback(blob);
}
return;
}
// 创建一个reader
const reader = new FileReader();
// 将图片转成base64格式
reader.readAsDataURL(file);
// 读取成功后的回调
reader.onloadend = (e) => {
const result = e.target.result;
// 解决重复图片上传无效问题:先清除
document.getElementById("uploadIcon").value = "";
// 图片处理
const img = new Image();
img.src = result;
console.log("未压缩图片", result.length);
img.onload = () => {
if (callback) {
callback(img);
}
};
};
},
},
};
复制代码
图片压缩
export default {
methods: {
compress(img) {
// 默认按比例压缩
const width = img.width;
const height = img.height;
const scale = width / height;
// 生成canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = this.width || width;
canvas.height = this.height || width / scale || height;
// 铺底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, width, height);
// quality值越小,所绘制出的图像越模糊。
let quality = 0.1; // 默认图片质量为0.1,进行最小压缩
if (this.quality && this.quality <= 1 && this.quality > 0) {
quality = this.quality;
}
const base64 = canvas.toDataURL("image/jpeg", quality);
return base64;
},
},
};
复制代码
base64 转 Blob
将以 base64 的图片 url 数据转换为 Blob
export default {
methods: {
dataURLtoBlob(dataUrl) {
const arr = dataUrl.split(",");
const mime = arr[0].match(/:(.*?);/)[1];
const bStr = atob(arr[1]);
let n = bStr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bStr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
},
};
复制代码