前因
环境
Vue3 + typescript + ant-design-vue 2.0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // 父组件 <template> <Form ref="formRef" :model="formState" :labelCol="{ style: 'width: 70px' }" :rules="rules"> <FormItem label="标 题" name="title"> <Input v-model:value="formState.title" placeholder="请输入文章标题" /> </FormItem> <FormItem label="封 面" name="themeImgs"> <UploadCover v-model:value="formState.themeImgs"></UploadCover> </FormItem> </Form> </template>
<script lang="ts"> import { defineComponent, ref } from 'vue'; import UploadCover from '@/components/UploadCover.vue'; export default defineComponent({ setup() { const formRef = ref(); const rules = { themeImgs: [ { required: true, message: '请上传封面', trigger: 'change' } ] }; return { formRef, rules } } }) </scirpt>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| // 子组件 <template> <a-upload v-model:file-list="fileList" list-type="picture-card" class="avatar-uploader" :show-upload-list="false" action="/apps-resource-app/content/image/imageUpload" :before-upload="beforeUpload" @change="handleChange" > <img v-if="imgUrl" :src="imgUrl" class="upload-image" /> <div v-else> <loading-outlined v-if="loading"></loading-outlined> <plus-outlined v-else></plus-outlined> <div class="ant-upload-text">Upload</div> </div> </a-upload> </template>
<script lang="ts"> import { defineComponent, reactive, UnwrapRef, ref, computed } from 'vue'; import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'; import { message } from 'ant-design-vue'; import { ImageResponse, Response } from '@/declares/interfaces';
interface FileItem { uid: string; name?: string; status?: string; response?: Response<ImageResponse>; url?: string; type?: string; size: number; originFileObj: any; }
interface FileInfo { file: FileItem; fileList: FileItem[]; }
export default defineComponent({ name: 'UploadCover', components: { LoadingOutlined, PlusOutlined, }, props: { value: String, }, setup(props, context) { const fileList = ref([]); const loading = ref<boolean>(false);
const handleChange = (info: FileInfo) => { if (info.file.status === 'uploading') { loading.value = true; return; } if (info.file.status === 'done') { loading.value = false; let response = info.file.response; if (response) { if (response.data) { context.emit('update:value', response.data.fileUrl); // 需要触发组件的 blur 事件,用于表单验证 context.emit('blur'); } else { message.error(response.resultMessage || '图片上传失败'); } } } if (info.file.status === 'error') { message.error('upload error'); loading.value = false; } };
const beforeUpload = (file: FileItem) => { ... };
const imgUrl = computed(() => props.value);
return { fileList, loading, imgUrl, handleChange, beforeUpload, }; }, }); </script>
|
这样写标题是起作用的,而封面的表单验证没有起作用,并且控制台会报出一个警告
解决
搞了很久都不知道是为什么,我一直以为themeImgs: [{ required: true, message: '请上传封面', trigger: 'change' }]
是会监听 themeImgs 这个变量的变化,从而触发校验,后来了解原理之后才知道,这样写,它会在组件上绑定一个change事件,第一个标题的校验没问题是因为 Input 有内部会触发 blur 方法,所以我只需要在我的 子组件里面也触发 change 方法就行了,这样改了之后发现警告还是存在,后面想到我是这样写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| // 子组件 <template> <a-upload v-model:file-list="fileList" list-type="picture-card" class="avatar-uploader" :show-upload-list="false" action="/apps-resource-app/content/image/imageUpload" :before-upload="beforeUpload" @change="handleChange" > <img v-if="imgUrl" :src="imgUrl" class="upload-image" /> <div v-else> <loading-outlined v-if="loading"></loading-outlined> <plus-outlined v-else></plus-outlined> <div class="ant-upload-text">Upload</div> </div> </a-upload> </template>
|
里面也有change事件,两者冲突了,所以我只需要在template之下加一个根 div 就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // 子组件 <template> <div> <a-upload v-model:file-list="fileList" list-type="picture-card" class="avatar-uploader" :show-upload-list="false" action="/apps-resource-app/content/image/imageUpload" :before-upload="beforeUpload" @change="handleChange" > <img v-if="imgUrl" :src="imgUrl" class="upload-image" /> <div v-else> <loading-outlined v-if="loading"></loading-outlined> <plus-outlined v-else></plus-outlined> <div class="ant-upload-text">Upload</div> </div> </a-upload> </div> </template>
|
这样就没问题了
参考资料
1.element ui form 验证机制