目录
一、背景
二、效果图
三、代码
一、背景
一名被组长逼着干前端的苦逼后端,在一个晴天霹雳的日子,被要求前端订单产品实现上传产品图片并立刻回显图片。
二、效果图
三、代码
<template><a-table :dataSource="dataSource" :columns="columns">/** 我这里只举例上传图片的插槽 */<template #base64Url="{ record }"><a-upload v-model:file-list="record.fileList" name="file" list-type="picture-card" class="product-upload" :show-upload-list="false" action="" @change="(file) => {return handleChange(file, record);}" :customRequest="(file) => {return requestUploadImg(file, record);}" accept="image/png, image/jpeg, image/jpg" :before-upload="beforeUpload"><img v-if="record.base64Url" :src="record.base64Url" /><div v-else><loading-outlined v-if="record.loading" class="ant-upload-icon" /><div class="ant-upload-text" v-if="record.loading">上传中</div><cloud-upload-outlined v-else class="ant-upload-icon" /><div class="ant-upload-text" v-if="!record.loading">支持上传 .jpg .jpeg .png 且小于 2MB 的图片</div></div></a-upload></template></a-table>
</template>
<script lang="ts">
import { LoadingOutlined, CloudUploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';interface FileItem {uid: string;name?: string;status?: string;response?: string;url?: string;type?: string;size: number;originFileObj: any;
}
interface FileInfo {file: FileItem;fileList: FileItem[];
}
function getBase64(img: Blob, callback: (base64Url: string) => void) {const reader = new FileReader();reader.addEventListener('load', () => callback(reader.result as string));reader.readAsDataURL(img);
}export default defineComponent({components: {LoadingOutlined,CloudUploadOutlined,},setup() {//这个只要file的状态发生改变就会触发const handleChange = (info: FileInfo, record) => {if (info.file.status === 'uploading') {record.loading = true;return;}if (info.file.status === 'done') {// Get this url from response in real world.getBase64(info.file.originFileObj, (base64Url: string) => {record.base64Url = base64Url;record.loading = false;});message.success('upload success');}if (info.file.status === 'error') {record.loading = false;message.error('upload error');}};//这个是上传图片之前的校验,限制图片的格式和大小。也可以在upload标签中使用accept和size设定用户上传时就禁止点击不符合条件的文件const beforeUpload = (file: FileItem) => {const isJpgOrPng =file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png';if (!isJpgOrPng) {message.error('You can only upload JPG file!');}const isLt2M = file.size / 1024 / 1024 < 2;if (!isLt2M) {message.error('Image must smaller than 2MB!');}return isJpgOrPng && isLt2M;};//覆盖默认的上传行为,自定义自己的上传实现const requestUploadImg = async (info, record) => {requestUploadImgApi({ file: info.file }).then((res) => {//必须转为blob格式(二进制文件),否则handleChange方法中接收的info.file中没有originFileObjconst urlData = URL.createObjectURL(info.file); //必须调用这个方法,否则上传组件的状态将一直是loading状态,传入的res, info.file, record位置不允许改变,且res必须是包含code、data、status、message等信息的responce,而不是data里的数据,否则会一直是error状态或者loading状态info.onSuccess(res, info.file, record); }).catch((err) => {info.onError();});};return {dataSource: [{key: '1',name: '产品1',desc: '产品描述1',base64Url: '',fileList: [],loading: false,},{key: '2',name: '产品2',desc: '产品描述2',base64Url: '',fileList: [],loading: false,},],columns: [{title: '产品名称',dataIndex: 'name',key: 'name',},{title: '产品描述',dataIndex: 'desc',key: 'desc',},{title: '产品图片',dataIndex: 'base64Url',key: 'base64Url',slots: { customRender: 'base64Url' }, //这个表示插槽,在html结构中可以自定义样式},{title: '操作',dataIndex: 'operation',key: 'operation',slots: { customRender: 'operation' },},],handleChange,beforeUpload,requestUploadImg,};},
});
</script>
<style lang="less">
.product-upload > .ant-upload {width: 204px;height: 125px;
}
.ant-upload-icon {font-size: 30px;opacity: 0.5;
}
</style>