使用AI帮我封装一个结合element Ui的上传组件。

下面是代码:

<template>
  <div>
    <!-- uploadUrl 指定上传地址 -->
    <!-- data 传递 CSRF token -->
    <!-- fileList 已经选择的文件列表 -->
    <!-- handleExceed 超过限制数量时的操作 -->
    <!-- handleBeforeUpload 开始上传前的操作 -->
    <!-- handleProgress 上传中的操作 -->
    <!-- handleSuccess 上传成功后的操作 -->
    <!-- handleError 上传失败后的操作 -->
    <!-- auto-upload 禁用自动上传 -->
    <!-- disable-remove 是否禁用删除按钮 -->
    <!-- show-file-list 是否显示文件列表 -->
    <el-upload
      class="upload-demo"
      ref="fileInput"
      :action="uploadUrl"
      :data="{ _token: csrfToken }"
      :file-list="fileList"
      :on-exceed="handleExceed"
      :before-upload="handleBeforeUpload"
      :on-progress="handleProgress"
      :on-success="handleSuccess"
      :on-error="handleError"
      :auto-upload="false"
      :disable-remove="uploading || fileList.length === 0"
      :show-file-list="false"
    >
      <!--  disabled 是否禁用添加按钮 -->
      <el-button slot="trigger" :disabled="!canAddFile || uploading" icon="el-icon-upload" size="small">{{
        buttonText
      }}</el-button>
      <div v-if="error" class="error-message">{{ error }}</div>
      <!-- 显示错误信息 -->
    </el-upload>
    <!-- 遍历已经选择的文件列表并展示 -->
    <div v-for="item in fileList" :key="item.uid" class="file-item">
      <div class="file-info">
        <span>{{ item.name }}</span>
        <span>({{ formatSize(item.size) }})</span>
        <!-- 格式化文件大小 -->
      </div>
      <div class="file-actions">
        <!-- 预览按钮,仅支持图片和视频类型 -->
        <el-button
          type="primary"
          icon="el-icon-view"
          @click.stop="previewFile(item)"
          :disabled="!isImage(item)"
          size="small"
        ></el-button>
        <!-- 删除按钮 -->
        <!-- uploading 是否正在上传 -->
        <el-button
          type="danger"
          icon="el-icon-delete"
          @click.stop="removeFile(item)"
          :loading="uploading"
          size="small"
        ></el-button>
      </div>
    </div>
    <!-- 文件预览对话框 -->
    <el-dialog :visible.sync="previewVisible" :append-to-body="true" :fullscreen="true" :show-close="false">
      <img :src="previewUrl" v-if="isImage(previewUrl)" class="preview-image" />
      <!-- 图片预览 -->
      <video :src="previewUrl" v-else-if="isVideo(previewUrl)" controls class="preview-video"></video>
      <!-- 视频预览 -->
    </el-dialog>
    <!-- 上传进度条 -->
    <el-progress
      v-if="uploading"
      :percentage="uploadPercentage"
      color="#409EFF"
      text-inside
      stroke-width="18"
      style="margin-bottom: 10px"
    ></el-progress>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  props: {
    uploadUrl: {
      type: String,
      required: true,
    },
    csrfToken: {
      type: String,
      required: true,
    },
    allowedFileTypes: {
      type: Array,
      default: () => ['image/jpeg', 'image/png', 'image/gif', 'video/mp4', 'video/webm', 'video/ogg'],
    },
    allowedFileSize: {
      type: Number,
      default: 5,
    },
    maxCount: {
      type: Number,
      default: 5,
    },
    buttonText: {
      type: String,
      default: '上传文件',
    },
  },
  data() {
    return {
      fileList: [], // 已经选择的文件列表
      uploading: false, // 是否正在上传
      error: null, // 错误信息
      previewVisible: false, // 预览对话框是否可见
      previewUrl: null, // 当前预览的文件 URL
      uploadPercentage: 0, // 上传进度百分比
    }
  },
  computed: {
    canAddFile() {
      // 计算属性:是否可以添加新的文件
      return this.fileList.length < this.maxCount
    },
  },
  methods: {
    handleExceed(files) {
      // 超出限制数量时的操作
      this.$message.warning(`最多只能上传 ${this.maxCount} 个文件`)
    },
    handleBeforeUpload(file) {
      // 开始上传前的操作
      if (!this.isAllowedFileType(file)) {
        this.$message.error('不支持的文件类型')
        return false
      }
      if (!this.isAllowedFileSize(file)) {
        this.$message.error(`文件大小不能超过 ${this.allowedFileSize} MB`)
        return false
      }

      const formData = new FormData()
      formData.append('file', file)
      formData.append('_token', this.csrfToken)

      axios
        .post(this.uploadUrl, formData, {
          onUploadProgress: (progressEvent) => {
            this.uploadPercentage = Math.floor((progressEvent.loaded / progressEvent.total) * 100)
          },
        })
        .then((response) => {
          this.handleSuccess(response.data.url, file)
        })
        .catch((error) => {
          this.handleError(error)
        })

      this.uploadPercentage = 0 // 重置上传进度
      this.uploading = true // 开始上传
      return true
    },
    handleSuccess(response, file) {
      // 上传成功后的操作
      this.fileList.push({
        uid: file.uid,
        name: file.name,
        size: file.size,
        url: response.url,
      })
      this.error = null
      this.uploading = false
    },
    handleError(error) {
      // 上传失败后的操作
      this.error = error.message
      this.uploading = false
      this.uploadPercentage = 0 // 重置上传进度
    },
    handlePreview(file) {
      // 点击预览按钮后的操作
      this.previewUrl = file.url
      this.previewVisible = true
    },
    removeFile(file) {
      // 点击删除按钮后的操作
      const index = this.fileList.indexOf(file)
      this.fileList.splice(index, 1)
    },
    isAllowedFileType(file) {
      // 检查文件类型是否在允许的范围内
      return this.allowedFileTypes.includes(file.type)
    },
    isAllowedFileSize(file) {
      // 检查文件大小是否在允许的范围内
      return file.size / 1024 / 1024 < this.allowedFileSize
    },
    isImage(file) {
      // 检查文件是否为图片
      return file.type.startsWith('image/')
    },
    isVideo(file) {
      // 检查文件是否为视频
      return file.type.startsWith('video/')
    },
    previewFile(file) {
      // 预览图片或视频
      if (this.isImage(file) || this.isVideo(file)) {
        this.handlePreview(file)
      }
    },
    formatSize(size) {
      // 格式化文件大小
      const units = ['B', 'KB', 'MB', 'GB', 'TB']
      let index = 0
      while (size >= 1024 && index < units.length - 1) {
        size /= 1024
        index++
      }
      return `${size.toFixed(2)} ${units[index]}`
    },
    handleProgress(event, file, fileList) {
      // 上传中的操作
      this.uploadPercentage = Math.floor((event.loaded / event.total) * 100)
    },
  },
}
</script>

<style scoped>
.upload-demo {
  margin-bottom: 20px;
}
.file-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px;
  border: 1px solid #ebeef5;
  margin-bottom: 10px;
  background-color: #f9fafc;
  border-radius: 4px;
}
.file-info {
  display: flex;
  align-items: center;
}
.file-info span:first-child {
  margin-right: 10px;
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-actions {
  display: flex;
  align-items: center;
}
.preview-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.preview-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.error-message {
  color: #f56c6c;
  margin-bottom: 10px;
}
</style>

二:如果你想在其他页面使用该组件,可以按照以下步骤进行操作:

  1. 引入组件
    在需要使用上传组件的页面中,首先需要引入该组件。假设你已经将上传组件保存为 Upload.vue 文件,则可以使用以下代码来引入组件:
import Upload from './Upload.vue';

其中,./Upload.vue 是上传组件的路径,具体路径需要根据实际情况进行调整。
2. 注册组件
引入组件后,需要将其注册为当前页面的局部组件。可以在当前页面的 components 选项中进行注册,例如:

export default {
  name: 'MyPage',
  components: {
    Upload,
  },
}

这里将上传组件命名为 Upload,并将其注册为 MyPage 组件的局部组件。
3. 使用组件
完成注册后,就可以在当前页面的模板中使用上传组件了。例如:

<template>
  <div>
    
    <upload :upload-url="uploadUrl" :csrf-token="csrfToken" />
  div>
template>

<script>
import Upload from './Upload.vue';
export default {
  components: { Upload },
  data() {
    return {
      uploadUrl: '/api/upload',
      csrfToken: '...',//可以从 cookie 中读取这个 CSRF token,并将其作为参数传递给服务器。
    };
  },
  // ...
};
script>

在上面的代码中,我们将 组件作为一个子组件插入到当前页面中,并传递了两个属性:upload-urlcsrf-token。其中,upload-url 指定了上传文件的接口地址,而 csrf-token 则是用于防止跨站请求伪造攻击的 CSRF token。需要根据具体的业务需求设置这两个属性。

总结:以上代码我没有在项目中运行 如有问题可以私信我,然后再做优化。

你可能感兴趣的:(ui,javascript,开发语言)