vue3 + ts + element plus 上传缩略图片、更换新图片、显示进度条

效果图:

vue3 + ts + element plus 上传缩略图片、更换新图片、显示进度条_第1张图片

vue3 + ts + element plus 上传缩略图片、更换新图片、显示进度条_第2张图片

思路:当上传的时候,才显示 进度条,上传完毕,不显示进度条。然后再显示 缩略图


 HTML部分:



      
      


      
      
       


      
      

        
        
           上传
        

      


JS部分:

//是否显示缩略图。当原文存在有缩略图的时候,取值 true ,当不存在值的时候,取值 false。
let showThumbnail = ruleForm.topic.picurl ? ref(true) : ref(false);

//缩略图网址。因为数据储存为 相对路径,前端显示的时候,添加上网址,成为绝对路径
let showThumbnailUrl = ruleForm.topic.picurl ? ref(import.meta.env.VITE_BASE_URL + ruleForm.topic.picurl) : ref('');


//是否显示进度条。默认为不显示,当上传图片的时候,才开始显示。上传完毕后,再改为不显示。
let showProcess = ref(false);

//进度条初始数据,开始为0,最后为 100
let progressPercent = ref(0);




//自动上传处理。有 http-request 触发。
const handleThumbnailUpload = (option: UploadRequestOptions) => {
  let oldThumbnail = ruleForm.topic.picurl;
  let { file } = option;
  let formData = new FormData();
  formData.append('file', file);
  uploadImage(formData)  //自定义 axios 上传
    .then((res) => {
      if (res.data.picurl) {
        ruleForm.topic.picurl = res.data.picurl; //把生成的缩略图赋值给表单数据,供给
        handleThumbnailShow(res.data.picurl); //自定义函数,处理显示进度条、显示缩略图
        if (oldThumbnail) {
          removeImage(oldThumbnail); //从服务器上删除旧缩略图
        }
      } else {
        if (res && res.data.msg) {
          ElMessage.error(res.data.msg);
        } else {
          ElMessage.error('图片上传失败!');
        }
        resetProcess();
        return false;
      }
    })
    .catch(() => {
      resetProcess();
    });
};


// 有 on-change 触发,开始进度条计值
const handleThumbnailChange = (uploadFile: UploadFile) => {
  if (uploadFile.status === 'ready') {
    showProcess.value = true;//开始显示进度条
    let ms = 0;
    const interval = setInterval(() => {
      if (progressPercent.value >= 100) { //当达到 100 ,停止计值
        clearInterval(interval);
        return;
      } else if (ms >= 5000) {
        clearInterval(interval); //由于意外而上传失败,超过 5 秒,停止 计值
        return;
      }
      progressPercent.value += 1; //计算增加值,进度条
      ms += 50;
    }, 50);
  }
};


//人为设置进度条。当上传完毕后,再显示 进度条达到 100
const handleThumbnailShow = (url: string) => {
  setTimeout(() => {
    progressPercent.value = 100;
  }, 100);

  setTimeout(() => {
    showThumbnailUrl.value = import.meta.env.VITE_BASE_URL + url;
    showThumbnail.value = true;
    resetProcess();
  }, 1000);
};


//复原进度条为不显示
const resetProcess = () => {
  showProcess.value = false;
  progressPercent.value = 0;
};


//自定义限制上传图片类型
const handleThumbnailBeforeUpload = (rawFile: UploadRawFile) => {
  if (imageType.indexOf(rawFile.type) === -1) {
    ElMessageBox({
      type: 'error',
      title: '',
      message: '上传的文件必须是JPG、JPEG、PNG、GIF、BMP类型',
      showCancelButton: false,
      confirmButtonText: 'OK',
    });
    return false;
  } else if (rawFile.size / 1024 / 1024 > 10) {
    ElMessageBox({
      type: 'error',
      title: '',
      message: '图片大小不能超过 10MB',
      showCancelButton: false,
      confirmButtonText: 'OK',
    });
    return false;
  }
  return true;
};

axios 上传函数:

import request from '@/http/index';
import type { AxiosPromise, AxiosResponse, AxiosError } from 'axios';

export function uploadImage(formData: FormData): AxiosPromise {
  return new Promise((resolve, reject) => {
    request
      .post('/thumbnail/upload/' + Math.random(), formData, {
        headers: {
          'Content-Type': 'multipart/form-data;charset=UTF-8',
        },
      })
      .then((res: AxiosResponse) => {
        resolve(res);
      })
      .catch((error: AxiosError) => {
        reject(error);
      });
  });
}

export function removeImage(picurl: string | undefined): AxiosPromise {
  return new Promise((resolve, reject) => {
    if (picurl) {
      request({
        url: '/thumbnail/remove/' + Math.random(),
        method: 'delete',
        data: { picurl: picurl },
      })
        .then((res: AxiosResponse) => {
          resolve(res);
        })
        .catch((error: AxiosError) => {
          reject(error);
        });
    } else {
      reject();
    }
  });
}

element plush 文章表单变量设置:

const ruleForm: TopicPostForm = reactive({
  topic: { tid: 0, cid: 0, dir: '', title: '', keywords: '', channel: '', description: '', summary: '', version: '', picurl: '', content: '', filterHtml: 0, yn: 1 } as TopicPost,
  channelList: [] as TopicChannel[],
});

const setTopicContent = (topic: TopicPost, channelList: TopicChannel[]) => {
  ruleForm.topic.tid = topic.tid;
  ruleForm.topic.cid = topic.cid;
  ruleForm.topic.dir = topic.dir;
  ruleForm.topic.title = topic.title;
  ruleForm.topic.keywords = topic.keywords;
  ruleForm.topic.channel = topic.channel;
  ruleForm.topic.description = topic.description;
  ruleForm.topic.summary = topic.summary;
  ruleForm.topic.version = topic.version;
  ruleForm.topic.picurl = topic.picurl;
  ruleForm.topic.content = topic.content;
  ruleForm.topic.yn = topic.yn;
  ruleForm.channelList = resetChannelList(channelList);
};

以上内容,根据自己的实际情况,可以自由定义。与上传相关的只有一个缩略图网址:ruleForm.topic.picurl

element plush 上传功能文档

注意:action:请求 UR。在上传组件中,当后端处理网址的时候,on-success 也是无效的,不能触发,on-progress 也是无效的,不能触发。on-change 仅仅有个 ready 状态有效。

你可能感兴趣的:(vue.js,elementui,前端)