当前位置:网站首页>vant3+ts 封装uploader上传图片组件
vant3+ts 封装uploader上传图片组件
2022-06-12 17:41:00 【热忱学习】
因为项目中多次用到这个组件 所以就自己封装了下

vant的组件需要在

:after-read 之后把图片上传到服务器
手机上选择或者拍照 返回的格式是[{name:xxx,data:base64,xxxxx},{name:xxx,data:base64,xxxxx}]
而 组件的回显是根据flie对象或者URL

所以就需要上传前 把 返回的base64转成file对象

图片上传到接口前还需要把图片压缩一遍

整个组件的代码如下
公司的上传图片的逻辑是 第一步,把fileNames 上传到后台提供的接口 返回的格式是{url:xxx,path:xxx,contentType:xxx},第二步,把返回的url put请求把file对象传到后台才算是请求成功,第三步,在拿第一步返回的path传到后台返回图片的URL(我这里回显根据的是url)
代码里count 是等接口都请求完了才给父组件传值
<template>
<van-uploader v-model="imgList" :max-count="limit" :multiple="multiple" :before-delete="beforeDeleteBack"
:after-read="afterRead" :accept="fileType" :disabled="disabled" @click-upload="handleClick" />
</template>
<script lang="ts" setup>
import { reactive, ref, toRefs, watch, nextTick, unref } from 'vue'
import { Toast, Dialog } from 'vant'
import AjaxTestService from '@/api/test'
import { getPhoto } from '@/utils/nativeAPI'
import ImageCompressor from 'image-compressor.js'
import type {
UploaderProps,
UploaderInstance,
UploaderResultType,
UploaderFileListItem,
} from 'vant'
interface Props {
imgList: Array<any> //文件地址-双向绑定
limit?: number //文件个数
multiple?: boolean //是否多选
fileType?: string //文件类型
disabled?: boolean //是否禁用上传
}
const props = withDefaults(defineProps<Props>(), {
limit: 4,
multiple: true,
fileType: 'image/*',
disabled: false
})
const imgList = ref<Array<any>>([])
const emit = defineEmits<{
(e: "update:imgList", imgList: any): void;
(e: "fileList", filePath: any): void;
}>();
watch(
() => props.imgList,
val => {
console.log(unref(val), "watch监听imgList");
// console.log(imgList.value.length, "图片的长度");
imgList.value = val.map(v => {
if (typeof v == 'string') {
return { url: v }
}
else {
return v
}
});
},
{ immediate: true, deep: true }
);
//删除图片
function beforeDeleteBack(file: any, detail: any) {
console.log("删除操作:file", file, "detail,", detail)
console.log(imgList.value, "传过来的img")
// return new Promise<boolean>((resolve, reject) => {
Dialog.confirm({
confirmButtonText: '确认',
cancelButtonText: '取消',
message: '确认删除故障图片',
})
.then((res) => {
console.log(tempFile, "删除")
tempFile.splice(detail.index, 1)
imgList.value.splice(detail.index, 1)
emit("update:imgList", imgList.value);
Toast({
message: '删除成功',
icon: 'checked',
iconSize: '20px',
className: 'tipToast'
})
// resolve(true)
})
.catch((error) => {
// Toast({
// message: '已取消',
// })
// reject(error)
})
// })
}
//将base64转换为blob文件流
function dataURLtoBlob(dataurl: any) {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = window.atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
console.log(mime, "mime")
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
//再将blob转换为file
function blobToFile(theBlob: any, fileName: any) {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
//调用
// var blob = dataURLtoBlob(base64Data);
// var file = blobToFile(blob, imgName);
//将base64转file 对象 因为再ios 有适配问题所以不用此方法了。
function base64ToFile(urlData: any, fileName: string) {
let arr = urlData.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bytes = window.atob(arr[1]); // 解码base64
let n = bytes.length
let ia = new Uint8Array(n);
while (n--) {
ia[n] = bytes.charCodeAt(n);
}
//u8arr
return new File([ia], fileName, { type: mime });
}
//点击上传区域触发事件 先要把fanhuide blobToFile(v.data, v.name)
function handleClick() {
console.log("点击上传事件触发")
getPhoto((res: any) => {
console.log(typeof res, "选择回来的文件类型")
// console.log(res, "选择回来的文件")
if (typeof res == 'string') {
res = JSON.parse(res)
res = res.map((v: any) => {
return {
type: 'image/jpeg',
name: v.name,
file: blobToFile(dataURLtoBlob(v.data), v.name)
}
})
}
afterRead(res)
})
}
//上传前需要压缩图片
function compressFile(file: any, callback: (cres: any) => void) {
new ImageCompressor(file, {
quality: 0.4, //压缩质量
width: 500,
height: 500,
checkOrientation: false, //图片翻转,默认为false
success(result) {
console.log(result, "result压缩过的文件")
callback(result);
},
error(e) {
JSON.stringify(e)
}
})
}
//
function beforeRead() {
console.log("点击上传事件触发")
}
//上传文件至服务器
let tempFile: { file: { name: any; }; path: string; url: string; name: any, type: string }[] = []
function afterRead(file: any) {
console.log(file, "在afterRead")
if (file.length) { // instanceof Array 单选
tempFile = tempFile.concat(file)
} else { //多选
tempFile.push(file)
}
if (tempFile.length > 4) {
console.log(tempFile.length, "判断里tempFile的长度")
tempFile.splice(4)
}
console.log(typeof tempFile, "typeof tempFile")
console.log(tempFile, "tempFile处理完成")
console.log(tempFile.length, "tempFile处理完成的长度")
//浏览端这样循环没问题,手机上格式返回[{name:xxx,data:base64},{name:xxx}]
let parma = {
fileNames: tempFile.map((fileItem: { file: { name: any; }; }) => fileItem.file.name).join(",")
}
// console.log(parma, '打印传参')
//后台提供的接口获取临时路径
AjaxTestService.getUploadUrl(parma).then((res) => {
let count = 0
res.data.forEach((item: { url: any; path: any, contentType: string }, index: any) => {
tempFile[index].path = item.path
tempFile[index].type = item.contentType
//这一步是压缩
compressFile(tempFile[index].file, (cres: any) => {
console.log(cres, '压缩后的文件file')
//拿返回的url put 请求才算上传图片成功
AjaxTestService.uploadImg(item.url, cres, item.contentType).then(_res => {
console.log(_res, "上传成功")
//根据后台接口返回临时图片信息
AjaxTestService.getTempFileUrl({ pathNames: item.path }).then(resUrl => {
console.log(res, "获取临时url")
tempFile[index].url = resUrl.data[0]
count += 1
if (count == res.data.length) {
imgList.value = tempFile
emit("update:imgList", tempFile)
console.log(tempFile.length, "tempFile的长度")
console.log(tempFile, "3步接口走完 imgList")
}
})
}).catch(err => {
})
})
});
}).catch(err => {
})
}
defineExpose({
// handleForm
});
</script>
<style scoped lang="scss">
</style>边栏推荐
猜你喜欢
![Vulnhub[DC3]](/img/3a/1aa03e804d447d38e85807928fdb8f.png)
Vulnhub[DC3]

php 实现无限极分类树(递归及其优化)

"Upgrade strategy" of two new committers

Arm64栈回溯

How to win the "Olympic Games" in retail technology for jd.com, the learning tyrant of the "regular examination"?

Interesting LD_ PRELOAD

消息队列实战之队列优先级

office应用程序无法正常启动0xc0000142

全局锁、表锁、行锁

Application case of smart micro 32-bit MCU for server application cooling control
随机推荐
R language uses the sum function of epidisplay package to calculate the descriptive statistical summary information of the specified variables in dataframe under different grouped variables and visual
Memory control of node
R语言使用epiDisplay包的summ函数计算dataframe中指定变量在不同分组变量下的描述性统计汇总信息并可视化有序点图(名称、有效值个数、均值、中位数、标准差、最大值、最小值)
R语言使用ggplot2可视化dataframe数据中特定数据列的密度图(曲线)、并使用xlim参数指定X轴的范围
qemu+gdb小节
JDBC几个坑
C#操作数据库增查业务数据值内容案例学校表
Arm64棧回溯
Qiushengchang: Practice of oppo commercial data system construction
Kali2022安装armitage
Go variables
How to view, modify, and delete SSH
Are Huishang futures accounts reliable? Is the fund safe?
数据库SQL操作基础
566. reshaping the matrix
Cesium抛物线方程
Figma从入门到放弃
(3) Golang - data type
MySQL transaction introduction and transaction isolation level
Sizepolicy policy in layout management