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