Vue3+elementplus实现图片上传下载(最强实践)

 图片上传子组件:

实现照片的上传,预览,以及转成以逗号隔开的图片地址,即时监听,并发送消息到父组件。

<!-- 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值