图片上传子组件:
实现照片的上传,预览,以及转成以逗号隔开的图片地址,即时监听,并发送消息到父组件。
<!-- ImageUploader.vue -->
<template>
<div>
<el-upload class="avatar-uploader" :http-request="customUpload" :before-upload="beforeUpload"
:show-file-list="false" multiple>
<el-icon>
<Plus style="background-color: azure;" />
</el-icon>
</el-upload>
<div v-for="(image, index) in imageUrls" :key="index">
<el-image :src="image" style="width: 100px; height: 100px" fit="cover" :preview-src-list="[image]">
<template #placeholder>
<div class="image-slot">Loading<span class="dot">...</span></div>
</template>
</el-image>
<el-button @click="deleteImage(image)" el-icon="">
<el-icon>
<DeleteFilled />
</el-icon>
</el-button>
</div>
</div>
</template>
<script setup lang="ts" name="ImageUploader">
import { computed, ref, watch } from 'vue';
import { upload } from '@/api/file'
import { ElMessage } from 'element-plus'
import emitter from '@/utils/emitter'
// 上传文件,请求接口,并且将结果存储
function customUpload(file: any) {
let formData = new FormData();
formData.append('file', file.file)
upload(formData).then((response: any) => {
const imgUrl = response.data;
imageUrls.value.push(imgUrl);
})
}
// 图片url
const imageUrls = ref([]);
// 计算属性,用于生成逗号隔开的图片地址字符串
const commaSeparatedUrls = computed(() => imageUrls.value.join(','));
// 监听图片地址变化,即时发送最新数据给父组件
watch(imageUrls, () => {
console.log('发送图片地址', commaSeparatedUrls.value)
emitter.emit('send-imageUrls', commaSeparatedUrls.value)
}, { deep: true })
// 图片校验规则
const beforeUpload = (file: any) => {
const isJPGOrPNG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPGOrPNG) {
ElMessage.error('picture must be jpg/png format!')
return false
}
if (!isLt2M) {
ElMessage.error('picture size can not exceed 2MB!')
return false
}
return true
};
// 删除图片
const deleteImage = (imgUrl: any) => {
// 从imageUrls数组中删除指定的图片URL
imageUrls.value.splice(imgUrl, 1);
};
</script>
<style scoped> .avatar-uploader {
color: skyblue;
font-style: normal;
}
</style>
表单父组件:
引入图片上传子组件,接受消息,并实现挂载之后取消绑定事件,避免占用内存
<template>
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
class="demo-ruleForm" :size="formSize" status-icon>
<el-form-item label="类型">
<el-radio-group v-model="ruleForm.type">
<el-radio value="0">转租</el-radio>
<el-radio value="1">短租</el-radio>
<el-radio value="2">长租</el-radio>
<el-radio value="3">招租</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="标题" prop="tittle">
<el-input v-model="ruleForm.tittle" />
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="ruleForm.address" />
</el-form-item>
<el-form-item label="介绍" prop="content">
<el-input v-model="ruleForm.content" />
</el-form-item>
<el-form-item label="房间照片">
<ImageUploader />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">
Create
</el-button>
<el-button @click="resetForm(ruleFormRef)">Reset</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive, ref, onUnmounted } from 'vue'
import type { ComponentSize, FormInstance, FormRules } from 'element-plus'
import { type HouseInter } from '@/types/model';
import emitter from '@/utils/emitter'
import ImageUploader from '@/components/ImageUploader.vue'
const formSize = ref<ComponentSize>('default')
const ruleFormRef = ref<FormInstance>()
const ruleForm = reactive<HouseInter>({})
const rules = reactive<FormRules<HouseInter>>({
type: [{ required: true, message: '请选择房源类型', trigger: 'change' }],
tittle: [{ required: true, message: '请填写标题', trigger: 'change' }],
})
// 接受图片上传子组件的图片地址最新消息
emitter.on('send-imageUrls', (value: string) => {
ruleForm.housePhoto = value
console.log('接收图片地址', ruleForm.housePhoto)
})
onUnmounted(() => {
// 组件卸载之后,解绑事件
emitter.off('send-imageUrls')
})
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
</script>
<style scoped></style>
消息工具类
import mitt from 'mitt'
import { ref } from 'vue'
let emitter = mitt()
let num = ref(0)
// 绑定事件
emitter.on('add', () => {
console.log('add被调用了', num)
})
// 每隔1秒执行事件
setInterval(() => {
// emitter.emit('add')
}, 1000)
setTimeout(() => {
// 解绑事件
emitter.off('add')
}, 5000)
export default emitter