公司大佬封裝的上傳文件或圖片組件,吊打我這個小白碼農

之前寫過一個文件上傳組件,該組件可以實現圖片/文檔/視頻/其他格式的上傳,並且可以選擇文件後回顯到表單中。
下面的代碼是公司大佬寫的,我先搬過來並分析一下:

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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章