使用element的upload组件实现一个完整的文件上传功能(下)
作者:小土豆biubiubiu
掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d
简书:https://www.jianshu.com/u/cb1c3884e6d5
微信公众号:土豆妈的碎碎念(扫码关注,一起吸猫,一起听故事,一起学习前端技术)
码字不易,点赞鼓励哟~
本篇文章是《使用element的upload组件实现一个完整的文件上传功能(上)》的续篇。
话不多说,接着上一篇直接开始
一.功能完善—保存表格中每一列的文件列表状态
1.思路
保存表格中每一列的文件列表状态,这个功能是什么意思呢,我们先看下前面示例的效果。
在上面这个操作中,我们做了两件事:
1.给表格第一列的上传了一个附件图片
2.点击表格第二列、第三列、第四列的上传按钮,分别查看这三列的附件列表
那么最后的结果发现后三列的附件列表展示的都是第一列的附件图片,这个显然不符合正常的逻辑。仔细去看看我们的代码并且思考一下,也很快能知道这个问题出现的原因:我们给<el-upload>的file-list属性绑定了attachList数据。attachList这个值初始是空数组,当我们点击第一列的附件管理上传一张图片后,attachList数组就会增加一个元素。而所有上传按钮触发打开的弹框组件是同一个(我们页面中只有一个<el-upload>元素),而弹框组件绑定的文件列表数据attachList也是公用的,因此就会出现上面的情况。到这里也很容易能想到思路去解决这个问题:不同弹窗绑定的文件列表数据attachList分开保存。
那这个办法的言外之意就是需要在data中定义4个attachList,那定义四个数据,我们就得定义写四个<el-dialog>分别去绑定这个四个数据。
这个办法到是能解决问题,但是假如我们的表格有100行数据呢,我们难道要定义100个attachList,在写100个<el-dialog>吗?这显然就不现实了。
然后我换了个思路:定义一个数组去保存不同的文件列表数据。这样在每次点击上传按钮时,将该列的文件列表数据赋值给另外一个数据currentAttachList,然后我们的<el-dialog>组件只需要绑定这个currentAttachList数据即可。这样就省事多了。
最后就是保存不同的文件列表数据的数组,这个要怎么定义呢。实际上也很简单,我们可以将这个数据当做表格数据的一个属性定义在tableData中。
currentAttachList: [],
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}]
tableData中的attachList就是我们定义的文件列表数据。
数据定义好了之后,我们继续下面的工作。
2.上传按钮的点击事件修改
根据前面我们写的一大堆的思路,可以知晓当我们点击【附件管理】按钮时,需要做两件事:
1.获取这一列表格数据中的附件列表,赋值给currentAttachList
2.将控制弹框显示的dialogVisible设置为true,让弹框显示
那我们之前写的点击【附件管理】按钮的事件处理程序如下:
<el-button size='small' type="primary" @click="dialogVisible = true">
上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
所以现在我们需要将点击事件改为函数调用。
在这之前呢,我们说了需要获取上传按钮对应那一列的attachList数据,那我们如何知道当前点击的上传按钮是属于表格的第几列呢?这个我们使用插槽就可以实现了。
<el-table-column
prop="attach"
label="附件管理"
width="180">
<template slot-scope="scope">
<!-- 上传按钮绑定click事件 -->
<el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
</template>
</el-table-column>
uploadBtnClick函数实现:
uploadBtnClick (index){
// 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
this.currentAttachList = this.tableData[index].attachList;
// 将控制弹框显示的dialogVisible设置为true,让弹框显示
this.dialogVisible = true;
}
这两件事情完成后呢,记得将<el-dialog>的file-list绑定的数据改为currentAttachList。
最后完整的App.vue组件代码如下
<template>
<div id="app">
<!-- element-ui Table表格组件 -->
<el-table
class="my-table"
:data="tableData"
stripe
style="width:725px;">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址"
width="180">
</el-table-column>
<!-- 添加一列附件管理(文件上传) -->
<el-table-column
prop="attach"
label="附件管理"
width="180">
<template slot-scope="scope">
<!-- 上传按钮绑定click事件 -->
<el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="附件管理"
:visible.sync="dialogVisible"
width="30%">
<!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:file-list="currentAttachList">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template> <script>
export default {
name: 'App',
data () {
return {
// 添加属性,默认值为false,表示弹框不显示
dialogVisible: false,
// 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
currentAttachList: [],
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}]
}
},
methods: {
uploadBtnClick (index){
// 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
this.currentAttachList = this.tableData[index].attachList;
// 将控制弹框显示的dialogVisible设置为true,让弹框显示
this.dialogVisible = true;
}
}
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin: 50px 30px;
text-align: center;
}
#app .el-dialog__header{
background:#EBEEF5;
border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
width: 100%;
}
</style>
<style scoped>
#app .my-table{
display: inline-block;
border: 1px solid #EBEEF5;
}
</style>
在浏览器中看下效果:
仔细的看几遍这个效果,描述一下我们的操作和结果:
1.在第四列上传了一张图片,完成之后关闭弹窗
2.点击第三列的上传按钮,获取tableData中第三列的attachList赋值给currentAttachList,此时第三列的attachList为空,所以currentAttachList也是空,所以第三列的附件列表展示为空,正常。(可以看到第三列的弹框点开后文件列表是一个从无到有的动画,是因为第四列上传了一个图片,currentAttachList包含一个元素,当点击第三列的上传按钮时将currentAttachList赋值为空,而element-ui提供的控件是包含动画的,所以就有了这个视觉上不太好的效果)
然而,我们最后还有一个操作:在查看完第三列的文件列表后,在返回点击第四列的附件管理按钮,查看第一个操作上传的文件列表。最后这个操作,我们惊奇的发现前面上传在第四列的文件列表丢了。
这个问题也比较好理解:上传完成后,需要将上传成功的文件信息保存到对应的那一列的attachList数组中。前面写的代码,我们只读取了tableData中的attachList,在上传成功以后却没有将文件的信息保存到attachList里面,那么每次重新点击【附件管理】按钮,从tableData获取的attachList永远是空,在赋值给currentAttachList,文件列表就什么也不会展示。现在我们可以接着修改代码了,需要修改的内容如下:
1.<el-upload>添加on-success钩子函数,当上传成功将本次上传的文件信息push到对应tableData.attachList
2.添加methods:uploadSuccess
关于这个uploadSuccess函数,它需要将上传成功的文件信息保存到对应的tableData.attachList,那我们就需要知道当前是一列的按钮触发的弹框。这个问题就是之前在uploadBtnClick函数传递的参数index,所以我们需要将这个index保存到vue的数据属性上,这样在uploadSuccess函数中也能用上。
data () {
return {
//当前点击打开弹框的按钮在表格中是那一列
currentIndex: 0,
}
}
uploadBtnclick方法需要新增加下面的代码
uploadBtnClick (index){
// 设置currentIndex
this.currentIndex = index;
},
uploadSuccess实现
uploadSuccess(response, file, fileList){
var currentIndex = this.currentIndex;
this.tableData[currentIndex].attachList.push({
'name':file.name
});
}
最终完整的App.vue代码如下
<template>
<div id="app">
<!-- element-ui Table表格组件 -->
<el-table
class="my-table"
:data="tableData"
stripe
style="width:725px;">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址"
width="180">
</el-table-column>
<!-- 添加一列附件管理(文件上传) -->
<el-table-column
prop="attach"
label="附件管理"
width="180">
<template slot-scope="scope">
<!-- 上传按钮绑定click事件 -->
<el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="附件管理"
:visible.sync="dialogVisible"
width="30%">
<!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:file-list="currentAttachList"
:on-success="uploadSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template> <script>
export default {
name: 'App',
data () {
return {
// 添加属性,默认值为false,表示弹框不显示
dialogVisible: false,
// 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
currentAttachList: [],
//当前点击打开弹框的按钮是那一列
currentIndex: 0,
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}]
}
},
methods: {
uploadBtnClick (index){
// 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
this.currentAttachList = this.tableData[index].attachList;
// 将控制弹框显示的dialogVisible设置为true,让弹框显示
this.dialogVisible = true;
// 设置currentIndex
this.currentIndex = index;
},
uploadSuccess(response, file, fileList){
var currentIndex = this.currentIndex;
this.tableData[currentIndex].attachList.push({
'name':file.name
});
}
}
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin: 50px 30px;
text-align: center;
}
#app .el-dialog__header{
background:#EBEEF5;
border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
width: 100%;
}
</style>
<style scoped>
#app .my-table{
display: inline-block;
border: 1px solid #EBEEF5;
}
</style>
浏览器查看结果:
可以发现,前面的问题已经被我们成功解决。
3.动画删除
现在呢,这个功能已经实现了。唯一不好的视觉效果就是文件列表的那个动画,我们将这个动画删除。
<style>
#app .el-upload-list li{
transition: none;
}
动画删除后的效果
可以看到,现在的效果就正常了。
三.功能完善—删除附件
删除文件这个功能,<el-upload>组件本身是支持的,只是在我们这种多文件上传的情况中,还需要添加一下代码。
我们先看一下组件本身提供的这个删除功能
我们的操作顺序和结果如下
①点击第四列上传按钮
②成功上传两张图片
③删除第二张图片
④关闭弹窗,查看第四列文件列表,文件列表显示正常
⑤点击第三列上传按钮,文件列表为空显示正常
⑥在点击第四列的上传按钮,发现前面删除的那张图片依然显示在文件列表中。
关于我们删除第四列的一张图片后,在第⑥步点击查看发现图片依然存在的这个问题很好解释,我们可以回头看一下uploadBtnclick函数的逻辑:
每次点击上传按钮,将对应的tableData.attachList赋值给currentAttachList。
而我们删除的时候,并没有删除对应的tableData.attachList中的数据,所以给currentAttachList的赋值操作导致文件列表展示的依然是之前的数据。
但是这里有一个疑惑的点就是第④个步骤:关闭弹窗,查看第四列文件列表,文件列表显示正常。这个就比较奇怪了,删除第二张图片后,按照前面我们梳理的uploadBtnclick函数的逻辑,此时文件列表应该还是会包含删除的那个文件。
关于这个问题,我们在uploadBtnClick函数中添加一些打印信息:
uploadBtnClick (index){
console.log('uploadBtnClick');
console.log("this.tableData[index].attachList");
console.log(this.tableData[index].attachList);
// 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
this.currentAttachList = this.tableData[index].attachList;
console.log("this.currentAttachList");
console.log(this.currentAttachList);
// 将控制弹框显示的dialogVisible设置为true,让弹框显示
this.dialogVisible = true;
// 设置currentIndex
this.currentIndex = index;
},
然后截图看一下步骤④中的打印信息:
可以看到,<el-upload>的file-list绑定的currentAttachList是包含两个元素(其中包含第③步删除的那个),但是文件列表却只显示了一个。
enmmmmmm,这个地方比较费解。
我们先处理第六个步骤中删除出现的异常显示。根据我们前面的梳理的逻辑,需要做两个修改
methods添加handleRemove函数处理删除数据的功能
<el-upload>添加on-remove钩子函数调用handleRemove
1.<el-upload>添加on-remove钩子函数调用handleRemove
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:on-remove="handleRemove"
:file-list="currentAttachList"
:on-success="uploadSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
2.methods添加handleRemove函数处理删除数据的功能
关于handleRemove函数要实现的功能,前面我们已经讲过:当删除一张图片后,删除对应的tableData.attachList中的数据。
关于这个功能有两个办法可以实现:
①遍历tableData.attachList中的文件信息,将需要删除的文件删除。
②on-remove钩子函数在调用时有两个参数:file和fileList。
file就是我们当前操作的文件,对于删除操作,file就是当前删除文件的信息;
fileList是操作完成后<el-upload>控件的的所有文件列表。
因此,可直接将fileList赋值给tableData.attachList。
我们分别使用两种办法去实现。
方法一:遍历tableData.attachList中的文件信息,将需要删除的文件删除
handleRemove(file, fileList){
var currentIndex = this.currentIndex;
var attachList = this.tableData[currentIndex].attachList;
var tempList = [];
for(var i = 0; i<attachList.length; i++){
if(file.name != attachList[i].name){
tempList.push(attachList[i]);
}
}
this.tableData[currentIndex].attachList = tempList;
}
方法二:直接将on-remove钩子函数的参数fileList赋值给tableData.attachList
handleRemove(file, fileList){
var currentIndex = this.currentIndex;
this.tableData[currentIndex].attachList = fileList;
}
可以任意选择一种实现,效果均相同
四.功能完善—验证文件名是否重复
element的多文件上传控件对重复的文件名并没有任何限制。
这个也不符合我们实际的开发场景。因此我们需要完善这个功能。
查看element文档,我们可以看到一个before-upload钩子函数
因此我们可以给<el-upload>控件添加before-upload钩子函数,在上传文件之前去判断文件是否重名,若有重名则阻止上传。
1.给<el-upload>控件添加before-upload钩子函数
<!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:on-remove="handleRemove"
:file-list="currentAttachList"
:on-success="uploadSuccess"
:before-upload="beforeUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
2.methods定义beforeUpload函数
beforeUpload(file){
var currentIndex = this.currentIndex;
//首先需要获取当前已经上传的文件列表
var list = this.tableData[currentIndex].attachList;
//循环文件列表判断是否有重复的文件
for(var i = 0;i<list.length;i++){
if(list[i].name == file.name){
this.$message.error(file.name + '文件名重复');
//记得一定要返回false,否则控件继续会执行上传操作
return false;
}
}
}
现在看下效果:
可以看到当文件名称重复时,会有一个错误提示并且成功阻止了这个重复文件的上传。
然而,当我们在此查看文件列表时,发现之前存在的文件在列表中丢失了。
这个原因是为啥呢?因为当bfeore-upload返回false之后,该组件会默认执行before-remove和on-remove这个两个钩子函数,我们在使用这个控件的时候只添加了on-remove这个钩子函数,为了证实这个默认行为,我们把before-remove这个钩子函数加上,并且在添加一些打印信息。
添加before-remove钩子函数
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:file-list="currentAttachList"
:on-success="uploadSuccess"
:before-upload="beforeUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
methods添加beforeRemove和一些打印信息
beforeRemove(file, fileList){
console.log('我是before-remove钩子函数,我被调用了');
},
handleRemove(file, fileList){
console.log('我是on-remove钩子函数,我被调用了');
var currentIndex = this.currentIndex;
var attachList = this.tableData[currentIndex].attachList;
var tempList = [];
for(var i = 0; i<attachList.length; i++){
if(file.name != attachList[i].name){
tempList.push(attachList[i]);
}
}
this.tableData[currentIndex].attachList = tempList;
},
然后就刚刚上传重复文件的那个操作我们看下打印信息
可以看到我们前面的说法已经被证实了。
同时,在深入一步思考一下,因为阻止上传重复的文件名,导致on-remove钩子函数被调用删除了对应tableData.attachList中的数据,所以当我们在此点击查看文件列表时【皇阿玛问号.jpg】已经不存在了。
那如何解决这个问题呢?
首先我们先将before-remove这个钩子函数完善一下:删除前给用户提示确认是否删除
beforeRemove(file, fileList){
return this.$confirm('此操作将永久删除' + file.name +'文件, 是否继续?');
},
然后,解决这个问题的关键是:当before-upload返回false后,不执行before-remove和on-remove这两个钩子函数里面的逻辑。
那我们看一下关于before-remove钩子函数的文档
可以看到,该钩子函数可以通过返回false停止删除,即可以阻止on-remove函数的调用。
所以我们将思路转到before-remove函数,只要能在before-remove里面做出一些判断,在上传重复的文件后使函数返回false。
那么现在需要做的就是在before-upload中得知上传了重复文件后,设置isRepeat标志值为true,在before-remove判断如果isRepeat这个标志值为true,就令该钩子函数返回false阻止on-remove函数的调用。
data () {
return {
//是否包含重复的文件名称,默认不包含值为false
isRepeat: false
}
},
methods: {
beforeRemove(file, fileList){
if(this.isRepeat == false){
return this.$confirm('此操作将永久删除' + file.name +'文件, 是否继续?');
}else{
// 这个逻辑表示包含重复的文件,这按照文档返回false可阻止文件继续上传
return false;
}
},
beforeUpload(file){
var currentIndex = this.currentIndex;
//首先需要获取当前已经上传的文件列表
var list = this.tableData[currentIndex].attachList;
//循环文件列表判断是否有重复的文件
for(var i = 0;i<list.length;i++){
if(list[i].name == file.name){
this.$message.error(file.name + '文件名重复');
//添加逻辑:得知上传了重复文件后,设置一个标志值为true,提供给beforeRemove函数使用
this.isRepeat = true;
//记得一定要返回false,否则控件继续会执行上传操作
return false;
}
}
}
}
然后我们看下效果:
这个结果看到之后有些吐血。
虽然当有重复文件上传时有了错误提示,但是这个重复发文件名却展示在了文件列表中。查看了打印信息,发现并没有调用on-remove钩子函数。
(这个文件上传控件这么鸡肋吗?还是我用法有误?)
没办法,也不知道啥原因,我只能在想想办法。
在转了转脑子,于是想尝试把before-remove中 else{ return false;}逻辑删除,这样当文件名称重复后,会自动调用on-remove钩子函数,我们把对isRepeat数据的判断加在on-remove钩子函数中去阻止删除操作。
beforeRemove(file, fileList){
if(this.isRepeat == false){
return this.$confirm('此操作将永久删除' + file.name +'文件, 是否继续?');
}
},
handleRemove(file, fileList){
console.log('我是on-remove钩子函数,我被调用了');
if(this.isRepeat == false){
var currentIndex = this.currentIndex;
var attachList = this.tableData[currentIndex].attachList;
var tempList = [];
for(var i = 0; i<attachList.length; i++){
if(file.name != attachList[i].name){
tempList.push(attachList[i]);
}
}
this.tableData[currentIndex].attachList = tempList;
}
},
再看下效果:
现在看起来这个效果是正常了,重复的文件没有上传也没有展示到文件列表中,在此点击查看也显示正常。
但是呢,还有最后一个问题,保证是最后一个问题了:
因为当文件重复后,isRepeat设置为了true,之后在没有地方修改这个数据,那么一个重复图片上传后,我们操作删除文件,此时isRepeat设置为true,按照逻辑before-remove中的删除提示不会执行,on-remove中的删除逻辑也不会执行。
所以呢,我们还需要在上传重复图片后,将this.isRepeat还原为false,那么我们将代码添加到on-remove函数中即可。
handleRemove(file, fileList){
console.log('我是on-remove钩子函数,我被调用了');
if(this.isRepeat == false){
var currentIndex = this.currentIndex;
var attachList = this.tableData[currentIndex].attachList;
var tempList = [];
for(var i = 0; i<attachList.length; i++){
if(file.name != attachList[i].name){
tempList.push(attachList[i]);
}
}
this.tableData[currentIndex].attachList = tempList;
}else{
this.isRepeat = false;
}
},
最后我们将打印信息删除,贴上完整的代码
src/App.vue
<template>
<div id="app">
<!-- element-ui Table表格组件 -->
<el-table
class="my-table"
:data="tableData"
stripe
style="width:725px;">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址"
width="180">
</el-table-column>
<!-- 添加一列附件管理(文件上传) -->
<el-table-column
prop="attach"
label="附件管理"
width="180">
<template slot-scope="scope">
<!-- 上传按钮绑定click事件 -->
<el-button size='small' type="primary" @click="uploadBtnClick(scope.$index)">
上传
<i class="el-icon-upload el-icon--right"></i>
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="附件管理"
:visible.sync="dialogVisible"
width="30%">
<!-- 将<el-upload>代码添加到<el-dialog>代码块中 -->
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:file-list="currentAttachList"
:on-success="uploadSuccess"
:before-upload="beforeUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template> <script>
export default {
name: 'App',
data () {
return {
// 添加属性,默认值为false,表示弹框不显示
dialogVisible: false,
// 设置当前文件列表数据currentAttachList,每次用户点击上传按钮,该数据就会被赋值为当前按钮那一列tableData中的attachList数据
currentAttachList: [],
//当前点击打开弹框的按钮在表格中是那一列
currentIndex: 0,
//是否包含重复的文件名称,默认不包含值为false
isRepeat: false,
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路',
attachList:[]
}]
}
},
methods: {
uploadBtnClick (index){
// 获取上传按钮对应那一列表格数据中的附件列表,赋值给currentAttachList
this.currentAttachList = this.tableData[index].attachList;
// 将控制弹框显示的dialogVisible设置为true,让弹框显示
this.dialogVisible = true;
// 设置currentIndex
this.currentIndex = index;
},
uploadSuccess(response, file, fileList){
var currentIndex = this.currentIndex;
this.tableData[currentIndex].attachList.push({
'name':file.name
});
},
beforeRemove(file, fileList){
if(this.isRepeat == false){
return this.$confirm('此操作将永久删除' + file.name +'文件, 是否继续?');
}
},
handleRemove(file, fileList){
if(this.isRepeat == false){
var currentIndex = this.currentIndex;
var attachList = this.tableData[currentIndex].attachList;
var tempList = [];
for(var i = 0; i<attachList.length; i++){
if(file.name != attachList[i].name){
tempList.push(attachList[i]);
}
}
this.tableData[currentIndex].attachList = tempList;
}else{
this.isRepeat = false;
}
},
beforeUpload(file){
var currentIndex = this.currentIndex;
//首先需要获取当前已经上传的文件列表
var list = this.tableData[currentIndex].attachList;
//循环文件列表判断是否有重复的文件
for(var i = 0;i<list.length;i++){
if(list[i].name == file.name){
this.$message.error(file.name + '文件名重复');
//添加逻辑:得知上传了重复文件后,设置一个标志值为true,提供给beforeRemove函数使用
this.isRepeat = true;
//记得一定要返回false,否则控件继续会执行上传操作
return false;
}
}
}
}
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin: 50px 30px;
text-align: center;
}
#app .el-dialog__header{
background:#EBEEF5;
border-bottom: 1px solid#EBEEF5;
}
#app .el-dialog{
text-align: left;
}
#app .el-upload,#app .el-upload .el-upload-dragger{
width: 100%;
}
#app .el-upload-list li{
transition: none;
}
</style>
<style scoped>
#app .my-table{
display: inline-block;
border: 1px solid #EBEEF5;
}
</style>
最后在来操作一波
五.总结
到此,《使用element的upload组件实现一个完整的文件上传功能》完成,该功能是结合前段时间在实际项目开发中做的一个功能,在这里单独拿出来总结。
在整个实践过程中,个人感觉element的upload组件,对多文件的上传功能还是不太友好,两个至今还没有探究明白的问题,在文中也以红色字体标出。
这两个问题虽然看着不影响什么,但心里总是有些不踏实。
使用element的upload组件实现一个完整的文件上传功能(下)的更多相关文章
- 使用element的upload组件实现一个完整的文件上传功能(上)
说到标题就有点心塞了,前段时间项目上需要实现一个文件上传的功能,然后就咔咔的去用了element的upload组件,不用不知道一用吓一跳哇. 在使用的过程中遇到了很多让意想不到的问题,后来也因为时间问 ...
- 用PHP实现一个简易版文件上传功能(超详细讲解)
1. php简化版的图片上传(没有各种验证) 1 2 3 4 <form action="" enctype="multipart/form-data" ...
- Java实现一个简单的文件上传案例
Java实现一个简单的文件上传案例 实现流程: 1.客户端从硬盘读取文件数据到程序中 2.客户端输出流,写出文件到服务端 3.服务端输出流,读取文件数据到服务端中 4.输出流,写出文件数据到服务器硬盘 ...
- [Vue]写一个简单的文件上传控件
这篇将介绍如何写一个简单的基于Vue+Element的文件上传控件. 控件将具有 1. 上传队列的列表,显示文件名称,大小等信息,可以显示上传进度实时刷新 2. 取消上传 使用Element的u ...
- 用python写一个简单的文件上传
用Pycharm创建一个django项目.目录如下: <!DOCTYPE html> <html lang="en"> <head> <m ...
- Grails笔记三:完整的文件上传实例
文件上传在web应用中是比较普遍的,相对于使用jsp等技术实现文件上传,Grails的文件上传着实让人喜爱,因为极其简单,让人看一遍就容易轻松记住!不多说,实例如下: 假设已有一个名为uploadFi ...
- element中文件上传
vue+element 文件操作 作者:一粒尘土 时间:2019-3-17 注:以下操作针对 vue-cli 目录 使用 组件常用参数 组件常用方法 上传文件 上传文件格式限制 回显文件 下载文件 删 ...
- vue+element UI + axios封装文件上传及进度条组件
1.前言 之前在做项目的时候,需要实现一个文件上传组件并且需要有文件上传进度条,现将之前的实现过程简单记录一下,希望可以帮助到有需要的人. 项目用的是Vue框架,UI库使用的是element UI,前 ...
- AntD框架的upload组件上传图片时使用customRequest方法自定义上传行为
本次做后台管理系统,采用的是 AntD 框架.涉及到图片的上传,用的是AntD的 upload 组件. 我在上一篇文章<AntD框架的upload组件上传图片时使用customRequest方法 ...
随机推荐
- 网络请求之jsonp封装
首先介绍下jsonp原理 浏览器因为同源策略的限制,在不同源的服务器通过我们传统axios是不能直接用来请求数据的(忽略代理),而src标签则不受同源策略的影响,所以我们需要动态的创建带有src的标签 ...
- 使用spring jpa 时,利用nativeQuery,获取数据,无需新建实体,按照别名返回Json数据
刚开始是这样写的 @Query(value = "SELECT ll.user_id id ,u.catong_img catong_img,ll.locationId location_i ...
- 规模化落地云原生,阿里云即将重磅亮相 KubeCon China
2019 年 6 月 24 日至 26 日, 由 Cloud Native Computing Foundation (CNCF) 主办的云原生技术大会 KubeCon + CloudNativeCo ...
- 2018-2-13-win10-uwp-如何让WebView标识win10手机
title author date CreateTime categories win10 uwp 如何让WebView标识win10手机 lindexi 2018-2-13 17:23:3 +080 ...
- Streamy 解决办法
- Export与import命令
模块功能主要由两个命令构成:export和import. export命令用于用户自定义模块,规定对外接口: import命令用于输入其他模块提供的功能,同时创造命名空间(namespace),防止函 ...
- 杂项-Java-百科:war-un
ylbtech-杂项-Java-百科:war-un 1.返回顶部 1. war是一个可以直接运行的web模块,通常用于网站,打成包部署到容器中.以Tomcat来说,将war包放置在其\webapps\ ...
- BiLSTM-CRF学习笔记(原理和理解) 维特比
BiLSTM-CRF 被提出用于NER或者词性标注,效果比单纯的CRF或者lstm或者bilstm效果都要好. 根据pytorch官方指南(https://pytorch.org/tutorials/ ...
- Python--day27--几个内置方法:__repr__()/__str__()/__del__()/__call__()/__getitem__/__setitem/delitem/__new__/__eq__/__hash__
repr方法() 双下方法__str__: 打印对象就相当于打印对象.__str__ __repr__(): __repr__是__str__的备胎,没有__str__的时候,就调用__repr__: ...
- H3C PPP协议的组成