看我如何使用Vue实现图片的上传以及大图预览功能

文章目录

  • 前言
  • 功能实现

前言

最近使用Vue作图片的上传,以及图片的列表展示功能,并且可以对图片进行放大预览处理,这里做一下记录总结,方便以后使用。

功能实现

下面的代码,笔者基于Vue.js,使用了element-ui组件类库实现的,功能包括:支持图片的上传图片类型以及图片大小校验图片列表展示图片大图预览功能图片空白处点击关闭大图功能。

废话不多说了,直接上代码:

<template>
  <div class="app-container">

    <el-tooltip slot="left" class="item" effect="dark" content="点击查看效果" placement="top-start">
      <el-button size="mini" type="primary" icon="el-icon-edit" @click="openModel"/>
    </el-tooltip>

    <!--表单组件-->
    <el-dialog
      :close-on-click-modal="true"
      :close-on-press-escape="true"
      :visible.sync="modelFlag"
      title="model弹框"
      width="50%"
      :fullscreen="false"
    >
      <el-form ref="formData" :inline="true" :model="formData" size="small"
               label-width="140px">
        <el-form-item label="file1" style="width: 500px;">
          <el-upload
            class="avatar-uploader"
            name="file"
            :action="uploadUrl"
            list-type="picture"
            :show-file-list="false"
            :on-preview="(file)=>handlePreview(file,'file1')"
            :on-remove="(file,fileList)=>handleRemove(file,fileList,'file1')"
            :on-success="(response, file)=> handleUploadSuccess(response, file,'file1')"
            :before-upload="beforeUpload"
          >
            <el-tooltip class="item" effect="dark" content="点击修改附件" placement="right">
              <img style="width: 250px;height:120px" v-if="formData.file1" :src="formData.file1" class="avatar" alt="">
              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
            </el-tooltip>
          </el-upload>
        </el-form-item>

        <!--第一种方式:点击右下角加号会放大图片-->
        <el-image v-show="formData.file1"
                  @click.native="handleClickItem"
                  src="https://img0.baidu.com/it/u=1713870962,188032507&fm=26&fmt=auto&gp=0.jpg"
                  :preview-src-list="[formData.file1]"
                  fit="fill"
                  class="el-avatar"
        />

        <el-divider></el-divider>
        <el-form-item label="file2" style="width: 500px;">
          <el-upload
            class="avatar-uploader"
            style="width: 250px;height:130px"
            :action="uploadUrl"
            :on-preview="(file)=>handlePreview(file,'file2')"
            :on-remove="(file,fileList)=>handleRemove(file,fileList,'file2')"
            :on-change="handleChange"
            :on-success="(response, file)=> handleUploadSuccess(response, file,'file2')"
            :file-list="showFileList.file2"
            :before-upload="beforeUpload"
            :limit="parseInt(1)"
            list-type="picture">

            <el-button v-show="formData.file2 === null || formData.file2 === ''" size="small" type="primary">
              点击上传
            </el-button>
          </el-upload>
        </el-form-item>
        <!--第二种方式:点击图片会放大预览图片-->
        <el-image-viewer v-if="file2BigFlag"
                         :on-close="()=>closePicturePreview('file2')"
                         @click.native="handleClickItem"
                         :url-list="[formData.file2]"/>

      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button type="success" @click="closeModel">取消</el-button>
        <el-button type="primary" @click="confirmSubmit">确认</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>

import apis from '@/store/modules/api'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'

export default {
  name: 'ImageFileUpload',
  components: {ElImageViewer},

  data() {
    return {
      modelFlag: false,
      formData: {
        //表单里附件数据
        'file1': null,
        'file2': null,
      },
      //附件展示(这里列表需要展示name和url属性,这里单独维护,方便处理)
      showFileList: {},

      //预览大图片标识,一般附件列表展示的看不清楚,会对图片进行放大处理
      file1BigFlag: false,
      file2BigFlag: false,

      //上传附件的url地址
      uploadUrl: `url`,
    }
  },

  methods: {
    /**
     * 打开model框,获取数据并赋值展示的附件列表
     */
    openModel(params) {
      //获取数据源
      this.formData.file1 = 'https://img0.baidu.com/it/u=3153405721,1524067674&fm=26&fmt=auto&gp=0.jpg';
      this.formData.file2 = 'https://img1.baidu.com/it/u=1474266791,210202337&fm=26&fmt=auto&gp=0.jpg';

      if (this.formData.file2) {
        this.showFileList.file2 = [{name: 'file2.jpeg', url: this.formData.file2}]
      }

      this.modelFlag = true
    },

    closeModel() {
      this.modelFlag = false
    },

    confirmSubmit() {
      this.$confirm('您确认提交吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        console.log(JSON.stringify(this.formData))
      }).catch(() => {

      })
    },

    /**
     * 附件上传成功后的处理
     */
    handleUploadSuccess(res, file, type) {
      if (type && type === 'file2') {
        this.formData.file2 = res.data.url
        //附件展示
        this.showFileList.file2 = [{name: 'file2.jpeg', url: this.formData.file2}]
      } else if (type && type === 'file1') {
        this.formData.file1 = res.data.url
        this.showFileList.file1 = [{name: 'file1.jpeg', url: this.formData.file1}]
      }
    },

    /**
     * 附件上传前的前置校验
     * @param file
     * @returns {boolean}
     */
    beforeUpload(file) {
      const fileTypeFlag = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'
      const fileTenM = file.size / 1024 / 1024 < 10

      if (!fileTypeFlag) {
        this.$message.error('上传附件格式只支持png、jpg、jpeg类型!')
      }
      if (!fileTenM) {
        this.$message.error('上传附件大小不能超过10MB!')
      }
      return fileTypeFlag && fileTenM
    },

    handleRemove(file, fileList, type) {
      //这个方法在上传文件时也会触发,所以这里做一下判断,只有主动删除文件才会触发
      if (file && file.status && file.status === 'ready') {
        return
      }

      if (type && type === 'file2') {
        this.formData.file2 = null
        this.showFileList.file2 = []
      } else if (type && type === 'file1') {
        this.formData.file1 = null
        this.showFileList.file1 = []
      }
    },

    /**
     * 点击文件列表中已上传的文件时的钩子(预览大图)
     */
    handlePreview(file, type) {
      if (type && type === 'file2') {
        this.file2BigFlag = true
      } else if (type && type === 'file1') {
        this.file1BigFlag = true
      }
    },

    /**
     * 预览图片关闭时事件
     */
    closePicturePreview(type) {
      if (type && type === 'file2') {
        this.file2BigFlag = false
      } else if (type && type === 'file1') {
        this.file1BigFlag = false
      }
    },

    handleChange(file) {
      console.log('handleChange' + file)
    },

    /**
     * 用户点击遮罩层关闭预览大图也是习惯性的常规操作,但 elementUI 并没有支持。
     两种思路:
     1、把hide事件绑定在遮罩层 dom
     2、直接调用 关闭按钮 上的 click 事件
     获取遮罩层dom很容易,hide事件就相对麻烦了,需要获取 vue实例子组件 image-viewer,再访问子组件的method。所以我使用了第二种方法
     */
    handleClickItem() {
      this.$nextTick(() => {
        // 获取遮罩层dom
        let domImageMask = document.querySelector('.el-image-viewer__mask')
        if (!domImageMask) {
          return
        }

        // 添加click监听事件,点击遮罩层时调用关闭按钮的 click 事件
        domImageMask.addEventListener('click', () => {
          document.querySelector('.el-image-viewer__close').click()
        })
      })
    },
  }

}
</script>

<style scoped>

/deep/ .el-image-viewer__close {
  color: white;
}

/*控制加号样式*/
/deep/ .el-image {
  width: 25px;
  height: 25px;
}

/*控制预览图片大小*/
/deep/ .el-image-viewer__img {
  height: 400px;
  width: 500px;
}

/deep/ .el-avatar {
  display: flex;
  position: absolute;
  left: 385px;
  top: 175px;
  color: white;
}

/deep/ .el-upload-list--picture {
  margin-top: -30px;
}

/deep/ .el-upload-list--picture .el-upload-list__item.is-success {
  width: 250px;
  height: 120px;
}

/deep/ .el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name {
  line-height: 80px;
  margin-top: 0;
  margin-left: 3px;
}

.avatar-uploader-icon {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  position: relative;
  overflow: hidden;
  display: inline-block;
  cursor: pointer;
  outline: white;
  font-size: 40px;
  color: #8c939d;
  width: 60px;
  height: 60px;
}

.el-icon-plus:before {
  text-align: center;
  vertical-align: middle;
}

</style>

写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,希望尽自己的努力,做到更好,大家一起努力进步!

如果有什么问题,欢迎大家一起探讨,代码如有问题,欢迎各位大神指正!

给自己的梦想添加一双翅膀,让它可以在天空中自由自在的飞翔!

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