漯河市文章资讯

ElementPlus的el-upload组件使用方式(图片上传)

2026-04-02 10:45:02 浏览次数:2
详细信息
Element Plus 的 el-upload 图片上传组件使用指南

Element Plus 的 el-upload 组件是一个功能强大的文件上传组件,支持图片上传、拖拽上传、预览等功能。下面详细介绍其使用方式。

基本安装与引入

npm install element-plus
// 完整引入
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)

// 或按需引入
import { ElUpload, ElButton, ElIcon } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'

基本图片上传示例

<template>
  <el-upload
    action="https://jsonplaceholder.typicode.com/posts/"
    :on-success="handleSuccess"
    :on-error="handleError"
    list-type="picture"
  >
    <el-button type="primary">点击上传</el-button>
  </el-upload>
</template>

<script setup>
const handleSuccess = (response, file, fileList) => {
  console.log('上传成功', response, file)
}

const handleError = (error, file, fileList) => {
  console.error('上传失败', error)
}
</script>

完整功能示例

<template>
  <div class="upload-demo">
    <h3>图片上传示例</h3>

    <!-- 基础图片上传 -->
    <div class="section">
      <h4>1. 基础图片上传</h4>
      <el-upload
        class="upload-demo"
        action="https://jsonplaceholder.typicode.com/posts/"
        :on-preview="handlePreview"
        :on-remove="handleRemove"
        :before-remove="beforeRemove"
        :on-exceed="handleExceed"
        :on-success="handleSuccess"
        :on-error="handleError"
        :before-upload="beforeUpload"
        list-type="picture"
        :limit="3"
        :file-list="fileList"
        :headers="headers"
        :data="uploadData"
        accept=".jpg,.jpeg,.png,.gif"
      >
        <el-button type="primary">点击上传</el-button>
        <template #tip>
          <div class="el-upload__tip">
            只能上传jpg/png/gif文件,且不超过2MB
          </div>
        </template>
      </el-upload>
    </div>

    <!-- 拖拽上传 -->
    <div class="section">
      <h4>2. 拖拽上传</h4>
      <el-upload
        class="upload-dragger"
        action="https://jsonplaceholder.typicode.com/posts/"
        drag
        multiple
        :on-success="handleSuccess"
        list-type="picture"
        accept="image/*"
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          将文件拖到此处,或<em>点击上传</em>
        </div>
        <template #tip>
          <div class="el-upload__tip">
            支持拖拽上传jpg/png/gif文件
          </div>
        </template>
      </el-upload>
    </div>

    <!-- 头像上传 -->
    <div class="section">
      <h4>3. 头像上传</h4>
      <el-upload
        class="avatar-uploader"
        action="https://jsonplaceholder.typicode.com/posts/"
        :show-file-list="false"
        :on-success="handleAvatarSuccess"
        :before-upload="beforeAvatarUpload"
      >
        <img v-if="imageUrl" :src="imageUrl" class="avatar" />
        <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
      </el-upload>
    </div>

    <!-- 自定义上传行为 -->
    <div class="section">
      <h4>4. 自定义上传(手动上传)</h4>
      <el-upload
        ref="uploadRef"
        class="upload-demo"
        action="#"
        :auto-upload="false"
        :on-change="handleChange"
        :file-list="customFileList"
        list-type="picture"
        multiple
      >
        <template #trigger>
          <el-button type="primary">选择文件</el-button>
        </template>

        <el-button class="ml-3" type="success" @click="submitUpload">
          上传到服务器
        </el-button>

        <template #tip>
          <div class="el-upload__tip">
            选择文件后需要手动点击上传按钮
          </div>
        </template>
      </el-upload>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { UploadFilled, Plus } from '@element-plus/icons-vue'

// 响应式数据
const fileList = ref([
  {
    name: 'food.jpeg',
    url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg'
  }
])

const customFileList = ref([])
const uploadRef = ref()
const imageUrl = ref('')

// 请求头和数据
const headers = reactive({
  Authorization: 'Bearer your-token-here'
})

const uploadData = reactive({
  userId: 123,
  category: 'avatar'
})

// 事件处理函数
const handleRemove = (file, fileList) => {
  console.log(file, fileList)
}

const handlePreview = (file) => {
  console.log(file)
  // 实际项目中可以打开图片预览弹窗
  // previewImage(file.url)
}

const handleExceed = (files, fileList) => {
  ElMessage.warning(
    `当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`
  )
}

const beforeRemove = (file, fileList) => {
  return ElMessageBox.confirm(
    `确定删除 ${file.name}?`
  ).then(() => true).catch(() => false)
}

const handleSuccess = (response, file, fileList) => {
  console.log('上传成功:', response)
  ElMessage.success('上传成功')

  // 实际项目中,可能需要从响应中获取图片URL
  // if (response.code === 200) {
  //   file.url = response.data.url
  // }
}

const handleError = (error, file, fileList) => {
  console.error('上传失败:', error)
  ElMessage.error('上传失败')
}

const beforeUpload = (file) => {
  const isImage = file.type.startsWith('image/')
  const isLt2M = file.size / 1024 / 1024 < 2

  if (!isImage) {
    ElMessage.error('只能上传图片文件!')
    return false
  }

  if (!isLt2M) {
    ElMessage.error('图片大小不能超过 2MB!')
    return false
  }

  return true
}

// 头像上传处理
const handleAvatarSuccess = (response, file) => {
  imageUrl.value = URL.createObjectURL(file.raw)
  // 实际项目中应使用服务器返回的URL
  // imageUrl.value = response.data.url
}

const beforeAvatarUpload = (file) => {
  const isImage = file.type.startsWith('image/')
  const isLt1M = file.size / 1024 / 1024 < 1

  if (!isImage) {
    ElMessage.error('只能上传图片文件!')
    return false
  }

  if (!isLt1M) {
    ElMessage.error('头像图片大小不能超过 1MB!')
    return false
  }

  return true
}

// 自定义上传
const handleChange = (file, fileList) => {
  customFileList.value = fileList
}

const submitUpload = () => {
  uploadRef.value.submit()

  // 实际项目中可能需要自己实现上传逻辑
  // customFileList.value.forEach(file => {
  //   const formData = new FormData()
  //   formData.append('file', file.raw)
  //   // 发送请求
  //   axios.post('/upload', formData).then(response => {
  //     console.log('上传成功:', response)
  //   })
  // })
}
</script>

<style scoped>
.upload-demo {
  padding: 20px;
}

.section {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}

h3 {
  color: #303133;
  margin-bottom: 20px;
}

h4 {
  color: #606266;
  margin-bottom: 15px;
}

.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}

.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
  line-height: 178px;
}

.upload-dragger {
  width: 360px;
}
</style>

实际项目中与后端API集成

<template>
  <el-upload
    ref="uploadRef"
    class="avatar-uploader"
    :action="uploadUrl"
    :headers="headers"
    :data="uploadParams"
    :show-file-list="false"
    :on-success="handleSuccess"
    :on-error="handleError"
    :before-upload="beforeUpload"
    :on-progress="handleProgress"
  >
    <!-- 上传区域内容 -->
  </el-upload>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useUserStore } from '@/stores/user'
import axios from 'axios'

const userStore = useUserStore()
const uploadRef = ref()

// 计算属性:动态获取上传URL
const uploadUrl = computed(() => {
  return import.meta.env.VITE_API_BASE_URL + '/api/upload/image'
})

// 请求头(携带token)
const headers = computed(() => {
  return {
    'Authorization': `Bearer ${userStore.token}`,
    'Content-Type': 'multipart/form-data'
  }
})

// 上传参数
const uploadParams = {
  type: 'avatar',
  timestamp: Date.now()
}

// 自定义上传函数(不使用action属性)
const customUpload = async (options) => {
  const { file, onProgress, onSuccess, onError } = options

  const formData = new FormData()
  formData.append('file', file)
  formData.append('type', 'avatar')

  try {
    const response = await axios.post('/api/upload/image', formData, {
      headers: {
        'Authorization': `Bearer ${userStore.token}`,
        'Content-Type': 'multipart/form-data'
      },
      onUploadProgress: (progressEvent) => {
        const percent = Math.round(
          (progressEvent.loaded * 100) / progressEvent.total
        )
        onProgress({ percent })
      }
    })

    onSuccess(response.data)
  } catch (error) {
    onError(error)
  }
}

// 分片上传示例
const chunkUpload = async (file) => {
  const chunkSize = 2 * 1024 * 1024 // 2MB
  const totalChunks = Math.ceil(file.size / chunkSize)
  const fileId = Date.now() + '-' + Math.random().toString(36).substr(2)

  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize
    const end = Math.min(start + chunkSize, file.size)
    const chunk = file.slice(start, end)

    const formData = new FormData()
    formData.append('file', chunk)
    formData.append('chunkIndex', i)
    formData.append('totalChunks', totalChunks)
    formData.append('fileId', fileId)
    formData.append('fileName', file.name)

    await axios.post('/api/upload/chunk', formData, {
      headers: {
        'Authorization': `Bearer ${userStore.token}`
      }
    })

    // 更新进度
    const progress = Math.round(((i + 1) / totalChunks) * 100)
    // 更新进度显示
  }

  // 所有分片上传完成后,通知服务器合并
  await axios.post('/api/upload/merge', {
    fileId,
    fileName: file.name,
    totalChunks
  }, {
    headers: {
      'Authorization': `Bearer ${userStore.token}`
    }
  })
}
</script>

常见属性说明

属性 说明 类型 默认值
action 上传的地址 string -
headers 设置上传的请求头部 object -
data 上传时附带的额外参数 object -
multiple 是否支持多选文件 boolean false
accept 接受上传的文件类型 string -
limit 最大允许上传个数 number -
auto-upload 是否在选取文件后立即上传 boolean true
file-list 上传的文件列表 array []
list-type 文件列表的类型 string text
drag 是否启用拖拽上传 boolean false
disabled 是否禁用 boolean false
on-preview 点击文件列表中已上传的文件时的钩子 function -
on-remove 文件列表移除文件时的钩子 function -
on-success 文件上传成功时的钩子 function -
on-error 文件上传失败时的钩子 function -
on-progress 文件上传时的钩子 function -
on-change 文件状态改变时的钩子 function -
before-upload 上传文件之前的钩子 function -
before-remove 删除文件之前的钩子 function -

注意事项

跨域问题:如果上传地址与当前站点不同域,需要后端支持CORS 文件大小限制:需要在before-upload中手动校验 文件类型限制:使用accept属性或before-upload中校验 上传进度:需要后端支持返回进度信息 安全性:上传的文件需要做安全检查,防止恶意文件上传 图片预览:大图片建议使用缩略图,避免性能问题

总结

Element Plus 的 el-upload 组件提供了丰富的图片上传功能,通过合理配置属性和事件处理函数,可以满足大多数图片上传需求。在实际项目中,通常需要结合后端API进行适当的定制和优化。

相关推荐