记录用vue用原生input写图片上传

如果项目中,因为各种因素导致无法用UI组件完成文件上传,需要用原生input标签完成可以采用如下方式

功能如下

  • 1.input介绍
  • 2.修改上传input样式
  • 3.多个文件上传(批量上传+多次累计上传)
  • 4.图片删除
  • 5.图片大图查看

一.input上传介绍

type:设置为file才能有上传功能
accept:允许上传的文件类型
multiple:批量上传(一次上传多张)想要上传多个文件需要在选择文件时,按住Ctrl进行多选

贴出html代码:

 <input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" />

二.修改input样式

文件上传input的默认样式如图


文件上传input的默认样式

针对input标签设置一些样式不会起作用(比如去掉黑色边框之类的),所以我们采用如下方式:

  1. 先隐藏type = "file"的元素,添加一个type="button"的元素
  2. 把上传按钮的样式写到type="button"的元素上
  3. 在type="button"的元素上绑定点击事件
    代码如下:
    1.html 部分
 <div class="demo-upload-btn">
     <!--上传input-->
     <input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" />
      <!--加一个相机图标-->
     <div  class="camera"></div>
     <!--点击上传的按钮-->
     <input type="button" class="btn" @click="clickFile" />
  </div>

2.JS部分

<script>
  clickFile (type) {
      const input = document.querySelector('#file' + type)
      input.click()
   }
</script>

3.css部分

<style lang="less">
.demo-upload-btn {
    position: relative;
    width: 60px;
    height: 60px;
    background: #fff;
    border: 1px dashed #d7dde4;
    border-radius: 4px;
    text-align: center;

    overflow: hidden;
    transition: border-color 0.2s ease;
    .file { // 将type="file"隐藏
      display: none; 
    }
    .btn { //type="button"设置样式
      position: absolute;
      top: 0;
      left: 0;
      width: 60px;
      height: 60px;
      background: rgba(0, 0, 0, 0);
      z-index: 10;
      border: none;
      cursor: pointer;
    }
    .camera {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 28px;
      cursor: pointer;
      background-image: '你的icon';
    }
  }
</style>

然后上传的样式变成了


image.png

三.多个文件上传

1.获取文件上传的数据

给input="file"的标签加上input的change事件,获取上传后的文件数据

html 部分

 <div class="demo-upload-btn">
     <!--上传input-->
     <input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" @change="handleSuccess" />
      <!--加一个相机图标-->
     <div  class="camera"></div>
     <!--点击上传的按钮-->
     <input type="button" class="btn" @click="clickFile" />
  </div>

JS部分

<script>
   handleSuccess1 (e) {
      // 因为上传过程为实例,这里模拟添加 url
      console.log(e.target.files) //拿到了上传的文件,是个数组
    }
</script>

打印如下

image.png

如果是批量上传多张,FileList会是多条数据
image.png

2.实现在本地显示上传的文件/图片

HTML部分

<div class="demo-upload-box">
    <div class="demo-upload-image-box" v-if="imageUrlArr && imageUrlArr.length">
    <!--循环展示上传后的图片-->
        <div class="demo-upload-image" v-for="(item,index) in imageUrlArr" :key="index">
            <img :src="item">
            <div class="demo-upload-box-cover">
                <!--图片查看大图-->
                <div class="ios-eye-outline" @click.native="handleView(item)"></div>
                <!--图片删除-->
                <div class="ios-trash-outline" @click.native="handleRemove(item)"></div>
            </div>
        </div>
     </div>
      <!--图片上传-->
     <div class="demo-upload-btn">
         <input ref="uploadInput1" type="file" multiple id="file" accept="image/jpg,image/png" class="file" @change="handleSuccess">
         <div type="camera"></div>
         <input type="button" class="btn" @click="clickFile" />
    </div>
</div>

JS部分

// urlList作为公共变量,可以实现批量上传+多次累计上传
var urlList = []
handleSuccess1 (e) {
      // 因为上传过程为实例,这里模拟添加 url
      let file = e.target
      for (let i = 0; i < file.files.length; i++) {
        urlList.push(window.URL.createObjectURL(file.files.item(i)))
      }
      this.imageUrlArr = urlList
}

如图:


image.png

三.图片删除和查看大图

因为input中的files是只读,不能直接删除某一项,所以需要用一个变量接收上传的文件信息,所以上传方法和删除方法改造如下:

//公共变量记录上传文件:filesData
 handleSuccess (e) {
      let file = e.target
      for (let i = 0; i < file.files.length; i++) {
        this.imageUrlArr.push(window.URL.createObjectURL(file.files.item(i)))
        this.filesData.push(file.files[i])
      }
},
// 删除上传的案例图
    handleRemove (index) {
      this.imageUrlArr.splice(index, 1)
      this.filesData.splice(index, 1)
      this.$forceUpdate()
}
 // 查看大图
    handleView (index) {
      this.bigPicSrc = this.imageUrlArr[index]
 }

三.完整代码

<template>
  <div class="updata-component">
    <div class="demo-upload-box">
      <div class="demo-upload-image-box" v-if="imageUrlArr && imageUrlArr.length">
        <div class="demo-upload-image" v-for="(item,index) in imageUrlArr" :key="index">
          <img :src="item">
          <div class="demo-upload-box-cover">
            <Icon type="ios-eye-outline" @click.native="handleView(index)"></Icon>
            <Icon type="ios-trash-outline" @click.native="handleRemove(index)"></Icon>
          </div>
        </div>
      </div>
      <div class="demo-upload-btn">
        <input :ref="name" type="file" :multiple="multiple" :accept="accept" class="file" @change="handleSuccess">
        <Icon type="camera"></Icon>
        <input type="button" class="btn" @click="clickFile" />
      </div>
    </div>
    <!-- 查看大图 -->
    <div class="big-pic" v-if="bigPicSrc" @click.self="bigPicSrc = ''">
      <img class="" :src="bigPicSrc" />
    </div>
  </div>
</template>
<script>
export default {
  props: {
    multiple: {
      type: Boolean,
      default: () => {
        return false
      }
    },
    accept: {
      type: String,
      default: () => {
        return 'image/jpg,image/png'
      }
    },
    name: {
      type: String,
      default: () => {
        return 'uploadInput'
      }
    }
  },
  data () {
    return {
      bigPicSrc: '',
      imageUrlArr: [],
      filesData: []
    }
  },
  methods: {
    // 文件上传接收
    handleSuccess (e) {
      let file = e.target
      for (let i = 0; i < file.files.length; i++) {
        this.imageUrlArr.push(window.URL.createObjectURL(file.files.item(i)))
        this.filesData.push(file.files[i])
      }
    },
    clickFile () {
      const input = this.$refs[this.name]
      input.click()
    },
    // 删除上传的案例图
    handleRemove (index) {
      this.imageUrlArr.splice(index, 1)
      this.filesData.splice(index, 1)
      this.$forceUpdate()
    },
    // 查看大图
    handleView (index) {
      this.bigPicSrc = this.imageUrlArr[index]
    }
  }
}
</script>
<style scoped lang="less">
.updata-component {
  .demo-upload-box {
    display: flex;
    .demo-upload-image-box {
      display: flex;
    }
    .demo-upload-image {
      width: 60px;
      height: 60px;
      text-align: center;
      line-height: 60px;
      border-radius: 4px;
      position: relative;
      box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
      margin-right: 4px;
      .demo-upload-box-cover {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(0, 0, 0, 0);
      }
      &:hover {
        .demo-upload-box-cover {
          position: absolute;
          top: 0;
          bottom: 0;
          left: 0;
          right: 0;
          background: rgba(0, 0, 0, 0.3);
        }
        .demo-upload-box-cover .ivu-icon {
          color: #fff;
          font-size: 20px;
          cursor: pointer;
          margin: 0 2px;
        }
      }
    }
    .demo-upload-btn {
      position: relative;
      width: 60px;
      height: 60px;
      background: #fff;
      border: 1px dashed #d7dde4;
      border-radius: 4px;
      text-align: center;

      overflow: hidden;
      transition: border-color 0.2s ease;
      .file {
        display: none;
      }
      .btn {
        position: absolute;
        top: 0;
        left: 0;
        width: 60px;
        height: 60px;
        background: rgba(0, 0, 0, 0);
        z-index: 10;
        border: none;
        cursor: pointer;
      }
      .ivu-icon-camera {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-size: 28px;
        cursor: pointer;
      }
    }
  }
  .big-pic {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 9999;
    img {
      position: absolute;
      width: 700px;
      height: auto;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
  }
}
</style>
<style lang="less">
.ivu-form .ivu-form-item-label {
  font-size: 14px;
  color: #45484c;
}
</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容