首页 > 其他分享 >vue图片上传组件

vue图片上传组件

时间:2023-07-13 15:11:06浏览次数:48  
标签:vue const color border upload value file 组件 上传

<template>
  <div
    @dragover.prevent
    @dragenter.prevent="drag = true"
    @dragleave.prevent="drag = false"
    @drop.prevent="onDrop"
    @click="input.click"
    v-show="status === 'upload'"
    :class="drag ? 'upload-active' : ''"
    class="box upload">
    <input @change="selectChange" ref="input" type="file" />
  </div>
  <div v-show="status === 'uploading'" class="box uploading">
    <img :src="imgUrl" />
    <p>{{ progress }}%</p>
    <progress id="file" max="100" :value="progress"></progress>
    <p>文件上传中...</p>
    <button @click="cancel">取消</button>
  </div>
  <div v-show="status === 'finished'" class="box finished">
    <div @click="cancel" class="cancel"><i-material-symbols-close /></div>
    <img :src="imgUrl" />
  </div>
</template>
<script setup>
  import axios from 'axios'

  const status = ref('upload') // upload、uploading、finished
  const input = ref()
  const progress = ref(0)
  const imgUrl = ref('')
  const drag = ref(false)
  let cancelUpload = null

  const selectChange = e => {
    if (!e.target.files.length) return
    const file = e.target.files[0]
    if (!validateFile(file)) return

    status.value = 'uploading'
    imgUrl.value = URL.createObjectURL(file) // blob

    cancelUpload = upload(
      file,
      val => (progress.value = val),
      resp => {
        status.value = 'finished'
        imgUrl.value = resp.data.url
      }
    )
  }

  const validateFile = file => {
    const suffixArr = ['jpg', 'jpeg', '.png']
    const maxSize = 1024 * 1024 * 5
    if (file.name && file.size) {
      const suffix = file.name.split('.').pop()
      if (suffixArr.includes(suffix) && file.size <= maxSize) return true
    }
    return false
  }

  const upload = (file, onProgress, onFinish) => {
    // 获取上传进度,取消请求:https://juejin.cn/post/7127547763679559693
    const controller = new AbortController()
    const data = new FormData()
    data.append('file', file)
    data.append('bar', 'foo')

    axios
      .post('/upload', data, {
        headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' },
        onUploadProgress(e) {
          // 获取上传进度
          if (e.lengthComputable) {
            onProgress(Math.round((e.loaded * 100) / e.total))
          }
        }
      })
      .then(resp => onFinish(resp))

    // 取消上传
    return () => controller.abort()
  }

  const cancel = () => {
    cancelUpload && cancelUpload()
    status.value = 'upload'
    progress.value = 0
    drag.value = false
  }

  const onDrop = e => {
    selectChange({ target: { files: e.dataTransfer.files } })
  }
</script>
<style scoped lang="less">
  .box {
    position: relative;
    margin: 100px auto;
    width: 250px;
    height: 250px;
    box-sizing: border-box;
    border-radius: 5px;
  }

  img {
    position: absolute;
    left: 0;
    top: 0;
    z-index: -1;
    width: 100%;
    object-fit: cover;
  }
  .upload {
    border: 2px dashed #ccc;

    &:hover {
      border-color: #409eff;
      cursor: pointer;
    }

    input {
      display: none;
    }

    &::after {
      content: '+';
      position: absolute;
      font-size: 100px;
      color: #aaa;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
  }

  .upload-active {
    background-color: rgba(64, 158, 255, 0.3);
    border-color: #409eff;
  }

  .uploading {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    border: 2px solid #ccc;
    background-color: rgba(0, 0, 0, 0.5);

    p {
      color: #fff;
      font-size: 18px;
      margin: 10px;
    }

    progress {
      width: 200px;
      height: 8px;
      border-radius: 85px;
      background-color: #fff;

      &::-moz-progress-bar {
        background-color: #409eff;
      }
    }

    button {
      all: initial;
      color: #fff;
      cursor: pointer;
    }
  }

  .finished {
    border: 2px solid #ccc;
    cursor: pointer;

    .cancel {
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 25px;
      height: 25px;
      background-color: rgba(0, 0, 0, 0.6);
      right: 0;
      top: 0;
      border-radius: 3px 3px 0 3px;
      font-size: 22px;
      color: #fff;
    }
  }
</style>

标签:vue,const,color,border,upload,value,file,组件,上传
From: https://www.cnblogs.com/19BigData/p/17550519.html

相关文章

  • vue+vite项目在浏览器运行正常,在钉钉白屏报错,在嵌入的app里面白屏报错
    1.在钉钉直接打开本地跑的项目白屏并且报错UncaughtReferenceError:globalThisisnotdefined/@vite/client:135:7ReferenceError:globalThisisnotdefinedathttp://192.168.20.36:5173/@vite/client:135:7UncaughtSyntaxError:Unexpectedtoken./src/main.ts:19:38......
  • vue 模糊查询
    html代码<divid="root"><h3>人员列表</h3><inputtype="text"placeholder="请输入名字"v-model="keyWord"><ul><liv-for="(p,index)offilPersons"......
  • 视频直播源码,搜索页面布局(Wrap组件)
    视频直播源码,搜索页面布局(Wrap组件)classLayoutDemoextendsStatelessWidget{ constLayoutDemo({Key?key}):super(key:key); @override Widgetbuild(BuildContextcontext){  returnPadding(   padding:constEdgeInsets.all(10),   child:W......
  • 使用cropperjs进行头像的上传裁剪
    1.引入依赖npminstallcropperjs2.使用import'cropperjs/dist/cropper.css';importCropperfrom'cropperjs';3.页面及样式,这边我是参考这位up主的(https://blog.csdn.net/weixin_41897680/article/details/123606376),不过这位up主是使用的vue3,我将他修改成了vue2的语......
  • vue - 点击按钮上传文件功能的实现
    methods:{//点击调用上传方法asynchandleUpload(row){try{letfileList=awaitthis.getFile("",true);//参数1:选取文件类型如.pdf、.png、.doc文件,参数2、是否多选console.log(fileList);//上传文件可在此处进行}catch......
  • Vue 学习 Day2
    摘要:动态属性的限制当使用DOM内嵌模板(直接写在HTML文件里的模板)时,我们需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写: <a:[someAttr]="value">...</a> “someAttr”属性而非“someattr”,这段代码将不会  ......
  • vue3核心概念-Mutation-辅助函数
    你可以在组件中使用 this.$store.commit('xxx') 提交mutation,或者使用 mapMutations 辅助函数将组件中的methods映射为 store.commit 调用(需要在根节点注入 store)辅助函数只能在选项式API中使用<template><h3>Nums</h3><p>{{getCount}}</p><inputtype="......
  • ckeditor粘贴word图片自动上传组件
    ​ 如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>......
  • Nginx:client_body_temp_path 指令的上传文件测试
    结论硬盘必须要有上传文件3倍大小的剩余空间。否则会报错“nospaceleftondevice”。需要注意,这3份数据都会写到硬盘。大文件上传,实时观察硬盘剩余空间watch-n0.1"df-hm/",会看到很大的波动。默认临时文件路径文档Syntax: client_body_temp_pathpath[level1[lev......
  • Vue实现在线编辑excel、导入、导出(转)
    原文:https://www.baidu.com/link?url=AuyjwtPhSkYFpr8dpb-mdYLpniwQhc7URksdLNktJ-dFgYmR4eEv3VpuTWxEH1p37BdTjfnva4iKCX8_pZx4BgFMyFjgxtMT95FLe5N02vi&wd=&eqid=dc455e22000331bf0000000664af71c1概要Vue实现在线编辑excel、导入、导出整体架构流程luckysheet文档地址exceljs文......