vue3 文件上传进度条组件

需要在main.js中use一下

import UploadProgress from '@/components/UploadProgress/index.js'
const app = createApp(App).use(UploadProgress)

使用

复制代码
// 上传文件方法,$uploadProgress.show()为展示,close关闭,$uploadProgress在index.js中已经注册
const upLoadProgressNum = ref(0)
const upload = (params, type) => {
  proxy.$uploadProgress.show({
    title: '上传文件',
    hint: '文件正在上传请勿刷新或关闭页面',
    percentage: upLoadProgressNum
  })
  upload(params, (progressEvent) => {
    if (progressEvent.lengthComputable) {
      upLoadProgressNum.value = progressEvent.loaded / progressEvent.total * 100 //实时获取上传进度
    }
  }).then((res) => {
    const code = res.code
    const data = res.data;
    if (code === 200) {
      ElMessage.success('上传成功');
      proxy.$uploadProgress.close()
    } else {
      ElMessage.error(res.msg);
    }
  })
}
复制代码

index.vue文件

复制代码
<template>
  <div class="confirm-modal">
    <transition name="fade">
      <div class="modal-dialog" @click="clickMaskToClose ? handleCancel() : null" v-if="visible" @touchmove.prevent>
        <div class="modal">
          <div class="modal-title" v-if="title">
            {{ title }}
          </div>
          <div class="modal-content">
            <div class="lineBox">
              <div class="line" :style="{'width': parseInt(percentage)+'%'}">
              </div>
            </div>
            <div class="num">
              {{parseInt(percentage)}}%
            </div>
          </div>
          <div class="hint" v-if="hint">
            {{parseInt(percentage) === 100 ? '数据整在处理请耐心等待...' : hint}}
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
  import {ref, defineComponent, reactive, toRefs} from "vue";

  export default defineComponent({
    props: {
      visible: {
        type: Boolean,
        default: false,
      },
      title: {
        type: String,
        default: "提示",
      },
      percentage: {
        type: Number,
        default: 0,
      },
      hint: {
        type: String,
        default: '',
      },
      clickMaskToClose: {
        type: Boolean,
        default: false,
      }, // 点击遮罩是否隐藏
    },

    emits: {
      onConfirm: null,
      onCancel: null,
    },
    setup(props, context) {
      let percentage = ref(0)
      let tempData = Object.assign({}, props);
      const propsData = reactive(tempData);
      const handleConfirm = () => {
        propsData.visible = false;
        context.emit("onConfirm");
      };
      const handleCancel = () => {
        propsData.visible = false;
        context.emit("onCancel");
      };
      return {
        ...toRefs(propsData),
        handleCancel,
        handleConfirm
      };
    },
  });
</script>

<style lang='scss' scoped>
  .modal-dialog {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 9999;
    transform: translateZ(9999px);
    letter-spacing: 0;
    background: rgba(0, 0, 0, 0.3);
  }

  .modal {
    position: absolute;
    top: 40%;
    left: 50%;
    z-index: 9000;
    width: 350px;
    transform: translate(-50%, -50%);
    box-sizing: border-box;
    background: #fff;
    border-radius: 4px;
    padding: 15px;
  }

  .modal-title {
    font-size: 16px;
    line-height: 25px;
    color: #030303;
    overflow: hidden;
    text-overflow:ellipsis;
    white-space: nowrap;
  }
  .hint {
    font-size: 13px;
    color: #e6a23c;
  }
  .modal-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 16px;
    line-height: 21px;
    color: #5e5f64;
    padding: 10px 0;
    .lineBox {
      position: relative;
      width: 100%;
      height: 15px;
      background-color: #ebeef5;
      border-radius: 2px;
      .line {
        position: absolute;
        top: 0;
        left: 0;
        height: 15px;
        border-radius: 2px;
        background-color: #409eff;
        transition: width 0.5s;
      }
    }
    .num {
      text-align: right;
      width: 50px;
    }
  }

  .no-title-content {
    font-size: 16px;
    padding: 28px;
    color: #333333;
  }

  .modal-right {
    padding-right: 10px;
    width: 36px;
    background: #f2f2f2;
    color: rgba(0, 16, 38, 0.3);
    font-size: 12px;
    border-radius: 0 4px 4px 0;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
  }

  .split-line-top {
    height: 1px;
    transform: scale(1, 0.5);
    background: #e8eaef;
  }

  .modal-footer {
    width: 100%;
    display: flex;
    align-items: center;
    height: 52px;
    font-size: 16px;
    line-height: 52px;
    text-align: center;
  }

  .split-line-center {
    width: 1px;
    height: 100%;
    transform: scale(0.5, 1);
    background: #e8eaef;
  }

  .btn-cancel {
    flex: 1;
    color: #696d76;
  }

  .btn-confirm {
    position: relative;
    flex: 1;
    color: #409eff;
  }
</style>
复制代码

 

index.js文件

复制代码
import { createApp } from "vue";
import uploadProgressIndex from "./index.vue";

const UploadProgressPlugin = {};
let $vm;

const defaultsOptions = {
  title: "提示",
  content: "内容",
  hint: "",
  clickMaskToClose: false,
};

const initInstance = () => {
  const app = createApp(uploadProgressIndex);
  const container = document.createElement("div");
  $vm = app.mount(container);
  document.body.appendChild(container);
};

UploadProgressPlugin.install = (app) => {
  const uploadProgress = {
    show(options) {
      if (!$vm) initInstance();
      options = Object.assign({}, defaultsOptions, options);
      for (const i in options) {
        $vm[i] = options[i];
      }
      $vm.visible = true;
      return $vm;
    },
    close() {
      $vm.percentage = 0
      if ($vm) $vm.visible = false;
    },
  };
  app.config.globalProperties.$uploadProgress = uploadProgress;
};

export default UploadProgressPlugin;
复制代码

 

logo
 
posted @   奚奚奚  阅读(675)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示