记一次elementui图片上传功能的重构

很多年前做项目时写的笔记,https://segmentfault.com/q/1010000017387815 问题起因在这里,今天偶然登录的时候有朋友在问我这个问题,就找到很多年前的笔记,方便大家吧~也许这么久了已经不需要了也说不定呢~

1. 拖拽的实现

1.dom操作

原本已经封装好的elementui来说,它的图片是一个fileList的数组,而拖拽的话,需要对dom进行操作,因此,我们首先想到的是能否取到img的src并将其放在一个div中,循环遍历显示出我们上传后的图片(下文中的fileArray只是一个假定值,代表我们在data里面定义的这个model值)

<div v-for="item in fileArray">
    <img src="item中存放的地址">    
</div>

这里要说的是,已经上传成功的response值和我们在上传图片成功时的返回值的数据结构并不一样。因此我们需要想办法取其共同点并且构造成一个新的数组,得到我们的fileArray。

fnBsnUploadPicSuccess(response, file, fileList) {
    if (response && response.result && response.result.res_path) {
        this.fileArray = this.fileArray.concat(response.result);
    }
}

2.拖拽

这个直接利用组件去实现,最开始的时候我选用的是vue.draggable,star还不错,效果也有,但是问题出现了,保存之后的结果依然是未排序之前的?这,难道它只实现了拖拽效果,而没有实现排序之后的数据结构的改变?尴尬了。我要去怎么搞?再搞一插件?给每个类都加一个class?来存储这排序之后的东西么?网上查了很久,也没有发现特别有用的,有些垂直列表之类的可以利用偏移值,然而我这是不确定的一个个排列下来的行内元素啊。突然转机,发现一个感觉还可以的插件,既能排序,也能保存,开心。立马抛弃了之前的vue.draggable,换上了新的vue-dragging。效果也是棒棒哒~开心!好景不长!当我把这个插件用到同一个页面中的另一个功能相同的组件中时,报错了!这里面一个非常关键的值就是找不到!悲伤的是,这个并不晓得去哪里解决这个问题,而且发现issue里面也有和我类似的问题,,,悲伤,,,好吧,再次回归到vue.draggable,star这么多一定是有的它的道理,而且人家应该也会考虑到这种问题吧。认真看了它的文档,重要的是down下它的demo。好吧,傻的人家有model用来存放他们的顺序。

<draggable v-model="myArray" :options="{draggable:'.item'}">
    <div v-for="item in fileArray">
    <img src="item中存放的地址">    
</div>
</draggable>

其中myArray就是用来存放顺序的数组,options呢暂时还没有发现它的作用。折腾来折腾去又回到了原点。

  • 学习一个插件最快的方式是它的demo
  • 插件的话,一定要选择可用性可维护性更强的。
  • 文档要好好读

3.图片的查看

直接将图片放入一个对话框,并且通过查看按钮控制对话框的显示与隐藏即可。

// 点击查看图片,注意此时还是利用数组下标来实现
fnClickPreviewPic(index) {
    this.布尔值 = true;
    this.sImgUrl = 图片地址
},

4.删除

与查看相似利用数组的原生方法即可

// 删除图片
fnBsnRemovePic(index) {
    this.fileArray.splice(index, 1);
},

5. 类似elementui的遮罩层和按钮的实现

这个网站还不错,很多hover效果大家都可以好好参考一下
利用tranform和opacity,比较关键的点就是元素hover之后对其他标签做的效果。

<div class="mask mask1")>
    <i class="el-icon-zoom-in"></i>
    <i class="el-icon-delete"></i>
</div>

拖拽并没有单独做一个按钮,因为其实它的效果并不是你点到某个按钮才会去实现这个效果。而是随便点到图片的某个地方即可,因此只是将鼠标的样式改成了move。这样可能会和上面的按钮冲突,因此我们将按钮的点击区域设置为一个固定的很小的地方,在这里面cursor为pointer,而其他地方我们则给他换回move。

以上步骤都完成之后,看似很完美,但是如果你需要对上传的总数做限制,那么你就happy了,这个limit真的是脑细胞都要死光了。

2.让我想砸电脑的limit

elementui里面实现一个这个真的是很简单啊,如果你设置了limit为一个数之后,只要它超过这个数,就是走到on-exceed函数。然而,我们现在弃用了它,只保留了上传的功能,如果只是将它设置为一个固定值,是肯定不行滴。

think one

因为我们能得到这次上传的值,以及我们已经上传的值,如果它超过这个值,就抛出错误,这样好像很完美,ok,试之。ok,为limit绑定一个值num,并且在初始化时将它的值设置为总长度-已经上传的图片数量,每次上传成功或者删除图片时都去修改这个值。ok,开始时没有问题,可是当我们删除几个再次添加时候函数走到on-exceed。失败~

think two

不绑变量了,ok,我们直接给他设置成总长度-已经上传的图片数量,并且我打印了这个值,嗯嗯,看起来好像很符合要求,简单试了一下上传多个的,ok,完全没有问题啊,就在我以为问题解决了而窃喜的时候,问题又来了、、、,如果我此时已经上传了4张,限制数量为6张,limit此时为3,而我即使只是上传一张,也没有成功。。。各个环节都没有问题啊,到底是为什么。

think three

在on-success中直接对fileArray做剪切,只显示其中的前6个,ok,这样确实看起来起到了效果,但是问题是,这些图片已经全部上传成功,对后端服务的压力很大,也并不符合我们设计的初衷。

think four

before-upload,这个函数是我曾经一度想使用看看的,可以在上传图片之前对图片做处理。如果超出限制,可以避免think three中的问题,然而,这个函数每上传一张都会执行一次,我们可以去维护一个变量监测到底有没有超出limit,但是当我们批量上传的时候,它可能还是存在只是没有超出limit的图片上传成功,而后面的都失败了,这样的用户体验并不好。也许排在后面的才是我们想上传的。

think five

想来想去,还是要从limit入手。到底为什么删删传传几次之后即使 要上传的数量<limit还是会执行on-exceed函数呢???后面查了很多资料,有些不太记得了,elementui的源码中,封装的这个函数的源码,如果files的长度+fileList的长度>limit那么就会执行这个函数。ok算是有点思路了,毕竟知道问题处在哪里,就有一点点儿方向了。

删除上传的时候,我们并没有对fileList做操作。导致它可能会有一个累加的效果。因此,我们要对这一部分数据做处理。

limit长度=限制长度 - fileArray的长度 + fileList.length;

这大概是最核心的地方了。虽然只有一行代码。

自己测试了一下,暂时并没有发现什么问题。

3.写在最后

  • 也许当你想修改一个东西的时候,搞清它的原理很重要,毕竟知己知彼方能百战不殆
  • 要想学一个陌生的东西,demo是个不错的快速上手的方式
  • 选择是一个很重要的方式,有些东西不必坚持,不必备选,有些需要坚持。看它的star值不值得了。
  • 不得不说的是,写这个东西真的花费了我很多的时间,确实最后代码量并没有多少,让人觉得你可能有偷懒的成分在里面,但是我并不想因此被别人否定如果它的时间与代码的长度不成正比。因为我真的有认真思考这个东西。
  • 有些你觉得不可能的事情还是会实现,比如这个东西我真的很想放弃它
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值