公司大佬封装的上传文件或图片组件,吊打我这个小白码农

之前写过一个文件上传组件,该组件可以实现图片/文档/视频/其他格式的上传,并且可以选择文件后回显到表单中。
下面的代码是公司大佬写的,我先搬过来并分析一下:

SelectFileDome.vue

<template>
//	vue中要求必须要有一个最外层的标签包裹,而且只有一个
	<div>
	//这是个按钮,可以用于显示数据的按钮,点击事件后面有
		<el-button @click="showData">显示数据</el-button>
		//el-row是element-ui中的一行标签
		//type="flex"即代表是flex布局,justify="center"即代表横向居中
		<el-row type="flex" class="raw-bg" justify="center">
			<el-col :span="6"><h2>文件上传demo</h2></el-col>
		</el-row>
		<el-row type="flex" class="raw-bg" justify="center">
			<el-col :span="6">
			//此处为一个上传文件的弹窗,传入的属性:allow支持的扩展名,max最大支持的文件大小,单位为b
				<upload-file-dialog allow="png" :max="100000000"/>
			</el-col>
		</el-row>
		<el-row type="flex" class="raw-bg" justify="center">
			<el-col :span="16">
			//此处的el-divider,我在element-ui中没有查到,但是这个是一个分割线组件,content-position="left",代表文字在左侧,右侧部分用分割线充满
				<el-divider content-position="left">整个传入</el-divider>
			</el-col>
		</el-row>
		<el-row type="flex" class="raw-bg" justify="center">
			<el-col :span="12">
			//此处用到了一个子组件selectFiles,这个子组件中传递的属性有:
			//v-model="filePaths",这个是自己写的一个v-model,支持v-model的组件有input select text  textarea等,如果要自己写的话,需要满足两个要求,一个是要有value值,一个是要监听input或者update更新的方法。
			//files是用于接收选择的文件数组的,
			//limit是显示几个选择文件的输入框,默认为1个。
			//allow是需要选择的文件扩展名
			//up-title是展示出来的标题,可以是文字,也可以是+加号
			//max是允许上传文件的大小最大值
			//label是显示的标签名称
				<select-files v-model="filePaths" :files="files2" :limit="4" :type="1" allow="jpg,png,gif,jpeg" up-title="+" :max="1054000" label="选择图片">
			</el-col>
		</el-row>
		<el-row type="flex" class="row-bg" justify="center">
		//此处的el-divider,我在element-ui中没有查到,但是这个是一个分割线组件,content-position="left",代表文字在左侧,右侧部分用分割线充满
	      <el-col :span="16"><el-divider content-position="left">传入一个空数组</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="12">
	      //此处用到了一个子组件selectFiles,这个子组件中传递的属性有:v-model="filePaths",这个是自己写的一个v-model,支持v-model的组件有input select text  textarea等,如果要自己写的话,需要满足两个要求,一个是要有value值,一个是要监听input或者update更新的方法。
	      	//files是用于接收选择的文件数组的,
			//limit是显示几个选择文件的输入框,默认为1个。
			//allow是需要选择的文件扩展名
			//up-title是展示出来的标题,可以是文字,也可以是+加号
			//max是允许上传文件的大小最大值
			//label是显示的标签名称
	        <select-files :files="[]" :limit="4" :type="1" allow="jpg,png,gif,jpeg" up-title="+" :max="1054000" label="选择图片  " />
	      </el-col>
	    </el-row>
	     <el-row type="flex" class="row-bg" justify="center">
	     //此处的el-divider,我在element-ui中没有查到,但是这个是一个分割线组件,content-position="left",代表文字在左侧,右侧部分用分割线充满
		    <el-col :span="16"><el-divider content-position="left">上传一个图像</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="12">
	      //此处用到了一个子组件selectFiles,这个子组件中传递的属性有:v-model="filePaths",这个是自己写的一个v-model,支持v-model的组件有input select text  textarea等,如果要自己写的话,需要满足两个要求,一个是要有value值,一个是要监听input或者update更新的方法。
      	//files是用于接收选择的文件数组的,
		//limit是显示几个选择文件的输入框,默认为1个。
		//allow是需要选择的文件扩展名
		//up-title是展示出来的标题,可以是文字,也可以是+加号
		//max是允许上传文件的大小最大值
		//label是显示的标签名称
	        <select-files :key="filePaths" v-model="filePaths" :file-urls="fileUrls" :files="files2" :limit="4" :type="1" allow="jpg,png,gif,jpeg" up-title="+" :max="1054000" label="选择图片  " />
	      </el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="16"><el-divider content-position="left">指定上传文件类型</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="12"><select-files img-style="width:400px;height:600px;line-height:600px" /></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="16"><el-divider content-position="left">上传多个图像</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="6">
	        <select-files :files="files" :limit="4" :type="1" allow="jpg,png,gif,jpeg" up-title="+" :max="1054000" />
	      </el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="16"><el-divider content-position="left">上传一个文件</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="6"><select-files /></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="16"><el-divider content-position="left">上传多个文件</el-divider></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="6"><select-files /></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="6"><h2>文件列表demo</h2></el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="18">
	      //select-file-list是选择文件列表的组件,
	      //allow:是显示需要上传的文件格式也就是扩展名
	      //max:是显示需要上传的文件的最大值限制
	      //select-file-type:是显示需要上传的文件的类型,此处的类型是前后端约定好的,1图片2文档3视频4文件5其他,图片的格式有很多种,png jpg gif jpeg等,此时如果需要再加以限制,则需要通过allow进行限制。
	        <select-file-list allow="jpg" :max="1024*1024" />
	      </el-col>
	    </el-row>
	    <el-row type="flex" class="row-bg" justify="center">
	      <el-col :span="18">
	      //select-file-list是选择文件列表的组件,
	      //allow:是显示需要上传的文件格式也就是扩展名
	      //max:是显示需要上传的文件的最大值限制
	      //select-file-type:是显示需要上传的文件的类型,此处的类型是前后端约定好的,1图片2文档3视频4文件5其他,图片的格式有很多种,png jpg gif jpeg等,此时如果需要再加以限制,则需要通过allow进行限制。
	        <select-file-list :select-file-type="1" />
	      </el-col>
	    </el-row>
	</div>
</template>
<script>
//以下代码为引入三个子组件,具体路径根据实际情况来
import selectFiles from '../../components/SelectFiles'
import SelectFileList from '../../components/SelectFiles/SelectFileList'
import UploadFileDialog from '../../components/SelectFiles/UploadFileDialog'

export default{
	name:'SelectFileDemo',
	//引入组件后,需要注册到当前页面中
	components:{UploadFileDialog ,SelectFileList ,selectFiles },
	data(){
		return{
			filePaths:'ssss,ssss',
			files2:[],
			files:[
				{
					url:'xxx',
					filePath:'xxx',
					suffix:'jpg'
				}	
			]
		}
	},
	methods:{
		showData() {
	      console.log('-filePaths---------------------------------')
	      console.log(this.filePaths)
	      console.log('-files---------------------------------')
	      console.log(this.files)
	      console.log('-files2---------------------------------')
	      console.log(this.files2)
	    }
	}
}
</script>

selectFiles.vue

//调用方法说明:filePaths和value在解析成数组的时候,是按同样的索引解析的,所以两个必须同时有且要求一致
//注意:files必须要放置一个空数组,必须要有,可以来用接收文件数据
<template>
//vue文件在template中需要有个最外层的div进行包裹,而且需要只有一个
  <div>
    <div class="source">
    //这些el开头的类名都是从element-ui中拷贝出来的,具体方法后续研究并说明
      <div class="el-upload-list el-upload-list--picture-card">
      //v-for循环的时候,为了保证key值的唯一性,有时需要进行拼接才可以
      //tabindex
      //imgStyle
        <span v-for="(item,index) in this.fileList" :key="index + item.filePath" tabindex="0" class="el-upload-list__item is-ready" :style="'border: none;' + imgStyle">
        //el-image是element-ui中的图片组件,这个组件的参数如下:
        //v=if是否显示
        //style样式
        //src图片的展示路径
        //fit图片的展示方式
          <el-image
            v-if="item.filePath"
            :style="imgStyle"
            :src="$store.getters.getConfigByKey('SYS_FILE_SERVER_PATH') + item.filePath"
            fit="fill"
          >
          //如果图片显示不出来,则会显示这个slot="error"错误的信息
          //type="flex"代表是flex布局,而且元素之间的间距为10
          //justify="center"代表的是flex中元素水平沿主轴方向居中展示
          //gutter代表的是flex中元素之间的间距为10
            <el-row slot="error" type="flex" justify="center" class="not-image-show" :gutter="10" style="background: #efefef">
              <el-col :span="8">
              //字符串的toUpperCase()方法是实现字符串的大写展示
              	<div class="text-suffix">{{ item.suffix.toUpperCase() }}</div></el-col>
              <el-col :span="1">|</el-col>
              <el-col :span="10" tag="div" class="text-filename">{{ item.fileName ? item.fileName : item.filePath }}</el-col>
            </el-row>
          </el-image>
          <div v-else tabindex="0" class="el-upload el-upload--picture-card" :style="'line-height: 300px;' + imgStyle" @click="show(index)">
            <i v-if="upTitle === '+'" class="el-icon-plus" />
            <span v-else style="font-size: 18px">{{ upTitle }}</span>
          </div>
		//如果图片存在的话,则可以进行图片的查看与删除操作
          <span v-if="item.filePath" class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview" @click="showFile(item)"><i class="el-icon-zoom-in" /></span>
            <span class="el-upload-list__item-delete" @click="deleteFile(index)"><i class="el-icon-delete" /></span>
          </span>
        </span>
      </div>
    </div>
	//element-ui中的弹出层操作
	//visible.sync是否展示弹出层
	//modal是否需要遮罩层,如果为true,则会展示出遮罩层
	//append-to-body  Dialog 自身是否插入至 body 元素上。嵌套的 Dialog 必须指定该属性并赋值为 true	
    <el-dialog :visible.sync="showDialog" :modal="true" width="1000px" :append-to-body="true">
      <select-file-list :type="type" :max="max" :allow="allow" @success="success" />
    </el-dialog>
  </div>
</template>
<script>
//引入选择文件列表的组件
import SelectFileList from './SelectFileList'
//定义一个空的对象,里面有三个值,分别是  文件类型  文件名称  文件扩展名
const emptyFileObj = {
  suffix: '',
  fileName: '',
  fileType: ''
}
export default {
//引入的组件需要进行注册
  components: { SelectFileList },
  //父组件可以传递的属性
  props: {
/* 允许选择的文件类型:从字典中获取key:1:图片;2:文档;3:音乐;4:视频*/
    type: {
      type: Number,
      default: null
    },
    /* 允许上传的文件后缀:如:jpg,png,gif*/
    allow: {
      type: String
      // default: 'jpg,png,gif,jpeg'
    },
    /* 最大上传文件容量*/
    max: {
      type: Number
      // default: 2097152
    },
    /* 最多选择多少个文件*/
    limit: {
      type: Number,
      default: 1
    },
    /* 回传或回显的文件数组*/
    files: {
      type: Array,
      default: null
    },
    /* 文件路径集合,多个路径使用【,】隔开*/
    filePaths: {
      type: String
      // require:true
    },
    /* filePaths 和 value 在解析成数组的时候,是按同样的索引解析的,所以两者必须同时有且要求一致*/
    value: {
      type: String,
      defaule: ''
    },
    imgStyle: {
      type: String,
      default: 'width:200px;height:300px'
    },
    upTitle: {
      type: String,
      default: '选择图片'
    },
    fileKey: {
      type: String
    }
  },
  data() {
    return {
      showDialog: false,
      currentIndex: -1,
      fileList: [],
      filePath: ''
    }
  },
  watch: {
    fileKey() {
    //截取数组的第一项
      this.fileList.splice(0)
      this.resetFiles()
      this.$forceUpdate()
    }
  },
  created() {
    this.fileList = this.files === null ? [] : this.files
    this.resetFiles()
  },
  methods: {
    success(fileData) {
      this.showDialog = false
      this.fileList[this.currentIndex] = fileData
      this.updateFilePaths()
    },
    show(index) {
      this.currentIndex = index
      this.showDialog = true
    },
    showFile(fileData) {
      window.open(this.$store.getters.getConfigByKey('SYS_FILE_SERVER_PATH') + fileData.filePath)
    },
    deleteFile(index) {
      for (var k in this.fileList[index]) {
        this.fileList[index][k] = ''
      }
      this.updateFilePaths()
      this.$forceUpdate()
    },
    updateFilePaths() {
      let paths = ''
      for (let i = 0; i < this.fileList.length; i++) {
        const file = this.fileList[i]
        if (file.filePath) {
          paths += file.filePath
          if (i !== this.fileList.length - 1) {
            paths += ','
          }
        }
      }
      this.$emit('input', paths)
    },
    resetFiles() {
      this.filePath = this.value
      if (this.fileList.length < 1 && this.filePath) {
        const paths = this.filePath.split(',')
        for (let i = 0; i < paths.length; i++) {
          const path = paths[i]
          this.fileList.push({
            filePath: path,
            suffix: path.substring(path.lastIndexOf('.') + 1, path.length)
          })
        }
      }
      if (this.fileList.length < this.limit) {
        for (let i = this.fileList.length; i < this.limit; i++) {
          this.fileList.push(emptyFileObj)
        }
      }
    }
  }
}
</script>
<style>
  .text-filename{
    word-break: break-all;
    word-wrap: break-word;
  }
</style>

SelectFileList

<template>
  <el-container style="min-width: 1000px">
    <el-header>
      <el-row type="flex" justify="between" :gutter="10" >
        <el-col :span="10">
          <el-input v-model="searchParams.fileName" class="width-full" placeholder="请输入文件名称" />
        </el-col>
        <el-col :span="8">
          <el-select v-model="searchParams.fileType" class="width-full" clearable value-key="id" :name="searchParams.fileType" placeholder="请选择文件类型" :disabled="type !== null ">
            <el-option
              v-for="item in fileTypeDict"
              :key="item.id"
              :label="item.value"
              :value="item.id"
            />
          </el-select>
        </el-col>
        <el-col :span="6" >
          <el-button type="primary" icon="el-icon-search" plain @click="searchFileList(0)">搜索</el-button>
          <upload-file-dialog :allow="allow" :max="max" @success="searchFileList(0)" />
        </el-col>
      </el-row>
    </el-header>
    <el-main class="main-center">
      <div v-if="fileList.length === 0">
        <el-row type="flex" class="row-bg no-data-row" justify="center" >
          <el-col :span="12" class="no-data-text" >这里空空如也,啥也没有哦!
            <upload-file-dialog :allow="allow" :max="max" @success="searchFileList(0)" />
          </el-col>
        </el-row>
      </div>
      <div v-else>
        <single-file-show v-for="fileData in fileList" :key="fileData.id" :file-data="fileData" @doSelect="doSelect(fileData)" />
      </div>
    </el-main>
    <el-footer>
      <el-pagination layout="total, prev, pager, next" :total="pageObj.total" @current-change="handleCurrentChange" /></el-footer>
  </el-container>
</template>
<script>
import { searchFileList } from '@/api/file'
import SingleFileShow from './SingleFileShow'
import UploadFileDialog from './UploadFileDialog'
export default {
  name: 'SelectFileList',
  components: { UploadFileDialog, SingleFileShow },
  props: {
    /* 允许选择的文件类型:从字典中获取key:1:图片;2:文档;3:音乐;4:视频*/
    type: {
      type: Number,
      default: null
    },
    /* 允许上传的文件后缀:如:jpg,png,gif*/
    allow: {
      type: String
      // default: 'jpg,png,gif,jpeg'
    },
    max: {
      type: Number
      // default: 2097152
    }
  },
  data() {
    return {
      searchParams: {
        fileName: '',
        fileType: this.type,
        page: 0,
        size: 9,
        sort: 'createTime,desc'
      },
      fileList: [],
      pageObj: {
        size: 0,
        total: 0,
        count: 0
      }
    }
  },
  computed: {
    fileTypeDict() {
      // console.log(this.$store.getters.getFileDicts('SYS_FILE_TYPE_DICT_ITEM'))
      return this.$store.getters.getFileDicts('SYS_FILE_TYPE_DICT_ITEM')
    }
  },
  created() {
    this.searchFileList()
  },
  methods: {
    searchFileList(page) {
      if (page || page === 0) {
        this.searchParams.page = page
      }
      searchFileList(this.searchParams).then(res => {
        this.fileList = res.content
        this.pageObj.total = res.totalElements
      })
    },
    handleCurrentChange(current) {
      this.searchParams.page = current - 1
      this.searchFileList()
    },
    doSelect(fileData) {
      const file = {}
      for (var k in fileData) {
        file[k] = fileData[k]
      }
      this.$emit('success', file)
    }
  }
}
</script>
<style scoped>
  .no-data-row{
    height: 300px;
    align-items: center;
  }
  .no-data-text{
    text-align: center;
    font-size: 15px
  }
  .main-center{
    min-height: 600px;
  }
</style>

UploadFileDialog

<template>
  <span>
    <el-tooltip class="item" effect="dark" placement="bottom-end">
      <div slot="content" style="font-size: 15px">
        仅允许上传后缀为【 <el-link type="primary">{{ allow }}</el-link>】格式的文件 <br><br>
        文件大小不允许超过【<el-link type="primary">{{ parseInt(maxFileSize / 1024) }}KB</el-link>/<el-link type="primary">{{ parseInt(maxFileSize / 1024 / 1024) }} M</el-link></div>
      <el-button type="success" plain icon="el-icon-upload" @click="show = !show">上传文件</el-button>
    </el-tooltip>
    <el-dialog :visible.sync="show" :append-to-body="true"  @close="closeDialog">
      <el-upload
        class="upload-demo"
        :action="action"
        :on-preview="handlePreview"
        :headers="headers"
        :list-type="listType"
        with-credentials
        show-file-list
        :accept="allowFileSuffix"
        auto-upload
        :on-success="onSuccess"
        :before-upload="beforeUpload"
        :limit="limit"
        :on-exceed="onExceed"
        multiple
      >
        <el-button type="primary" icon="el-icon-upload">{{ btnTitle }}</el-button>
        <div slot="tip" class="el-upload__tip">
          <p>仅允许上传后缀为【 <el-link type="success">{{ allow }}</el-link>】格式的文件</p>
          <p>文件大小不允许超过【<el-link type="success">{{ parseInt(maxFileSize / 1024) }}KB</el-link>/<el-link type="success">{{ parseInt(maxFileSize / 1024 / 1024) }} M</el-link></p>
        </div>
      </el-upload>
      <el-row type="flex" class="row-bg" justify="center">
        <el-col :span="6">
          <el-button v-show="flag" class="backbtn" type="success" size="small" @click="confirm()">确定</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </span>
</template>
<script>
import { getToken } from '@/utils/auth'
import store from '@/store'
export default {
  name: 'UploadFileDialog',
  props: {
    /* 允许上传的文件后缀:如:jpg,png,gif*/
    allow: {
      type: String,
      default: store.getters.sysConfig['FILES_ALLOWED_TO_UPLOAD']
      // default: 'jpg,png,gif,jpeg'
    },
    // 单位B
    max: {
      type: Number
      // default: 2097152
    },
    fileType: {
      type: Number
    },
    listType: {
      type: String,
      default: 'picture'
    },
    title: {
      type: String,
      default: '上传文件'
    },
    btnTitle: {
      type: String,
      default: '上传文件'
    },
    /* 最我允许上传文件个数*/
    limit: {
      type: Number,
      default: 5
    }
  },
  data() {
    return {
      show: false,
      headers: {
        'Authorization': getToken()
      },
      flag: false
    }
  },
  computed: {
    allowFileSuffix() {
      return '.' + this.allow.replace(/,/g, ',.')
    },
    maxFileSize() {
      if (this.max == null) {
        return this.$store.getters.sysConfig['FILES_ALLOWED_MAX_SIZE']
      }
      return this.max
    },
    action() {
      return this.$store.getters.baseUploadFile
    }
  },
  created() {
  },
  methods: {
    onSuccess(result, file, fileList) {
      if (result.status === 200) {
        this.flag = true
        file.url = result.data.url
      }
      this.$notify({
        title: result.message
      })
    },
    closeDialog() {
      if (this.flag === true) {
        this.$emit('success')
      }
    },
    confirm() {
      this.show = false
    },
    beforeUpload(file) {
      // 判断文件大小是否符合规范
      if (this.maxFileSize < file.size) {
        this.$notify({
          title: '文件大小超过最限制,最大上传【' + this.maxFileSize / 1024 + 'KB】当前文件大小为【' + file.size / 1024 + 'KB】'
        })
        return false
      }
      return true
    },
    onExceed(files, fileList) {
      this.$notify({
        title: '最多只能上传' + this.limit + '个文件'
      })
    }
  }
}
</script>
<style scoped>
  .el-row {
    margin-top: 20px;
  }
</style>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章