Vue3结合Element Plus封装上传图片功能

10 篇文章 2 订阅

前言

实现单个的图片上传
使用 Vue3Element Plus 实现图片的 删除 和 预览

LUpload 组件

  • 首先我们在 components 创建一个文件名为 LUpload.vue 的文件
  • 代码如下
<template>
    <!-- 
        此组件只解决单张图片上传
        1、添加图片上传时呈现出 loading 的一个状态
        2、添加在图片上传完成后,鼠标放在图片上呈现出 “图片预览”、“删除图片” 的效果
        3、自定义图片大小以及方形圆形图片
     -->
    <div class="l-upload" :class="round ? 'round' : ''">
        <!-- el-upload 组件 -->
        <el-upload class="avatar-uploader" :style="uploadStyle" :headers="headers" :action="action" :show-file-list="false"
            :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :on-progress="handleAvatarProgress"
            v-loading="uploadLoading">
            <div class="avatar" v-if="modelValue" @click.stop>
                <el-image class="image" :src="modelValue" ref="imageRef" />
                <!-- 鼠标 hover 是图片上方遮罩层 -->
                <div class="el-upload-actions">
                    <!-- 图片预览ICON -->
                    <div class="item" @click="handlePictureCardPreview">
                        <el-icon size="18" color="#fff">
                            <ZoomIn />
                        </el-icon>
                    </div>
                    <!-- 图片删除ICON -->
                    <div class="item" @click="handleRemove">
                        <el-icon size="18" color="#fff">
                            <Delete />
                        </el-icon>
                    </div>
                </div>
            </div>
            <el-icon v-else class="avatar-uploader-icon">
                <Plus />
            </el-icon>
        </el-upload>
        <!-- 实现图片大图预览 -->
        <!-- 注意 ElImageViewer 组件必须要使用v-if判断 -->
        <ElImageViewer v-if="isImageView" :url-list="srcList" @close="imageClose"></ElImageViewer>
    </div>
</template>

<script setup lang="ts">
import { defineProps, reactive, ref, toRefs, defineEmits } from 'vue'
import { Plus, ZoomIn, Delete } from '@element-plus/icons-vue' // 引入 Element 中的图标
import { ElImageViewer } from 'element-plus'; // 实现图片预览的组件,注意这是 element-plus 中的哦

import { getDomainName } from "@/utils/index"; // 获取 域名地址
import Cookies from 'js-cookie'

const props = defineProps({
    // 父组件 v-model 绑定的值
    modelValue: {
        type: String
    },
    // 图片上传时的地址
    action: {
        type: String,
        default: 'http://127.0.0.1:1024/image/upload'
    },
    // 定义 el-upload 组件的样式
    uploadStyle: {
        type: Object,
        default: {
            width: "200px",
            height: "200px",
        }
    },
    // 图片是否为圆形
    round: {
        type: Boolean,
        default: false
    }
})

const state = reactive({
    uploadLoading: false, // 图片文件大时 呈现出一个上传中的loading状态
    headers: { // el-upload 自定义 headers 头(根据自己的接口看是否需要)
        Authorization: Cookies.get('Token'),
        ContentType: 'application/json;charset=utf-8'
    },
    isImageView: false, // 图片预览时的状态
    srcList: [] as any // 图片预览列表(可以是多张)
})

const { headers, uploadLoading, isImageView, srcList } = toRefs(state)
const imageRef = ref()

const emit = defineEmits(['update:modelValue'])

// 预览图片
function handlePictureCardPreview() {
    state.isImageView = true
}

// 关闭图片预览
function imageClose() {
    state.isImageView = false
    state.srcList = [] // 每次关闭图片预览时清空一下
}

// 删除图片
function handleRemove() {
    emit('update:modelValue', "")
}

// 图片上传成功
function handleAvatarSuccess(response: any, file: any, fileList: any) {
    // response 上传成功返回的数据,根据自己的情况来写。
    let url = getDomainName() + response.data.url
    emit('update:modelValue', url)
    state.srcList.push(url)
    state.uploadLoading = false
}
// 图片上传之前
function beforeAvatarUpload() {

}

// 图片上传时
function handleAvatarProgress() {
    state.uploadLoading = true
}
</script>

<style scoped lang="scss">
.l-upload {
    ::v-deep .el-upload {
        width: 100%;
        height: 100%;
        border: 1px dashed #dcdfe6;
    }

    .avatar-uploader {
        .avatar {
            width: 100%;
            height: 100%;
            cursor: auto;
            position: relative;

            .image {
                width: 100%;
                height: 100%;
            }

            .el-upload-actions {
                top: 0;
                left: 0;
                cursor: auto;
                width: 100%;
                height: 100%;
                transition: 0.5s;
                position: absolute;
                background: rgba($color: #000000, $alpha: 0.5);
                opacity: 0;
                display: flex;
                align-items: center;
                justify-content: center;

                .item {
                    width: 30px;
                    height: 30px;
                    display: flex;
                    cursor: pointer;
                    align-items: center;
                    justify-content: center;
                }
            }

            &:hover {
                .el-upload-actions {
                    opacity: 1;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
            }
        }
    }
}

.round {
    ::v-deep .el-upload {
        border-radius: 50px;
        overflow: hidden;
    }
}
</style>

父组件,LUpload.vue的使用

  • 首先我们肯定需要先引入一下 LUpload.vue 组件了
<template>
    <div class="dashboard">
        <!-- LUpload组件 -->
        <LUpload v-model="url"></LUpload>
    </div>
</template>

<script setup lang="ts">
import { reactive, toRefs, ref, onMounted } from 'vue'
// 引入 LUpload 组件,不要照抄哦,看好自己的路径(如何组册为全局组件这里就不过多说了)
import LUpload from "@/components/LUpload/index.vue"

const state = reactive({
    url: ""
})

const { url } = toRefs(state)

onMounted(() => {

})

</script>

<style scoped lang="scss">
.bg {
    width: 100px;
    height: 100px;

}
</style>

接下来我们看一下效果吧

有点模糊,就这样看吧。
在这里插入图片描述

  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Vue3 Element Plus 文件上传组件封装: ```vue <template> <el-upload :class="uploadClass" :action="uploadUrl" :headers="uploadHeaders" :data="uploadData" :multiple="multiple" :limit="limit" :file-list="fileList" :auto-upload="autoUpload" :show-file-list="showFileList" :on-change="handleChange" :before-upload="beforeUpload" :on-exceed="handleExceed" :on-success="handleSuccess" :on-error="handleError" > <el-button :size="buttonSize" type="primary">{{ buttonText }}</el-button> <div slot="tip" class="el-upload__tip">{{ uploadTip }}</div> </el-upload> </template> <script> import { ref } from 'vue'; export default { props: { uploadUrl: { type: String, required: true }, uploadHeaders: Object, uploadData: Object, uploadClass: String, multiple: { type: Boolean, default: false }, limit: { type: Number, default: 3 }, fileList: { type: Array, default: () => [] }, autoUpload: { type: Boolean, default: true }, showFileList: { type: Boolean, default: true }, buttonSize: { type: String, default: 'medium' }, buttonText: { type: String, default: '点击上传' }, uploadTip: { type: String, default: '只能上传jpg/png文件,且不超过2MB' } }, setup(props, { emit }) { const uploadRef = ref(null); function handleChange(file, fileList) { emit('change', file, fileList); } function beforeUpload(file) { const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'; const isLt2M = file.size / 1024 / 1024 < 2; if (!isJPG) { this.$message.error('上传头像图片只能是 JPG/PNG 格式!'); } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 2MB!'); } return isJPG && isLt2M; } function handleExceed(files, fileList) { this.$message.warning(`当前限制选择 ${props.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${fileList.length} 个文件`); } function handleSuccess(response, file, fileList) { emit('success', response, file, fileList); } function handleError(error, file, fileList) { emit('error', error, file, fileList); } // 返回需要暴露给父组件的数据和方法 return { uploadRef, handleChange, beforeUpload, handleExceed, handleSuccess, handleError }; } }; </script> ``` 这个组件的主要功能是将 Element Plus 的 Upload 组件进行封装并暴露出一些常用的事件和方法,方便在父组件中进行调用。其中,`uploadUrl` 是必传的属性,用于指定上传接口的地址。其他属性都有默认值,并可以通过传递 props 进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值