element-ui如何防止重复提交的方法步骤


Posted in Javascript onDecember 09, 2019

先说对话框(Dialog)里的表单提交

错误方案

说起错误方案,比如,点击提交按钮,本地验证,验证通过立即让按钮不可点,这些没问题,而我的错误点概括是:在某个最后执行的回调函数的最后一行,我做了2个操作:1,隐藏Dialog,2,让提交按钮可点击。

这个方案看似没问题,做到了让对话框消失,又保证下一次打开Dialog之后,提交按钮是可点击的。但它错误在于:隐藏Dialog是一个动画过程,并不是瞬间消失,所以按钮恢复可点击之后,Dialog还没有彻底隐藏,所以只要你点得够快,就可以多点几次按钮。

正确方案

  1. 早在打开对话框的时候,将提交按钮可点击。做法是在<el-dialog>上加入open事件函数:@open="submitButtonDisabled = false",其中submitButtonDisabled是我控制提交按钮的变量,你可以改成你自己用的。
  2. 点击之后验证,通过则立即按钮不可点(this.submitButtonDisabled = true),不通过则不做任何针对按钮的处理。(这是铁律,下面会经常看到)
  3. 验证通过的话,最后执行的某个回调函数的最后一行,隐藏对话框。比如this.dialogFormVisible = false,这个变量你也要改成自己用的。

它的核心是2点:早在打开对话框的时候就让提交按钮可点击;验证通过的话,最后的回调函数不应该去管提交按钮恢复可点击的事,而是放到下一次打开对话框的时候才让提交按钮可点击。

再说不涉及对话框的提交

不涉及对话框,比如按钮在页面上直接存在,又分三种情况:

  1. 点击之后不跳转,但按钮消失
  2. 点击之后不跳转,按钮也不消失
  3. 点击之后跳转页面

即便是跳转页面,也是需要时间的,这个期间一样可以重复提交。不跳转页面的话,重复提交就更容易发生了。怎么办?

情况1:点击之后不跳转,但按钮消失

这种情况出现在小型提交场合,比如在表格中修改数据,表格中的某个单元格有一个修改按钮,点击之后按钮消失,只留下数据自己,而且,不允许有成功提示框,因为毕竟是小型提交场合,而且提交按钮消失就已经代表了成功。

element-ui如何防止重复提交的方法步骤

这就是三种不同的状态,依次是无数据时、编辑状态时、有数据时

这种情况的处理方案很简单:

  1. 点击之后验证,通过则立即不可点,不通过则不针对按钮处理
  2. 服务器返回结果之后,保存成功则按钮消失,保存失败则按钮依旧存在。无论成功失败,按钮都要变成可点击。由于这里按钮消失是瞬间发生,没有动画过程,所以就算按钮变回可点击,也因为它已经消失,因此不会造成重复提交。

这里引出一个问题,就是表格中的小型提交场合,Save按钮会有一竖列,如何准确给某个按钮设置不可点击呢?可以这样:

  1. 从服务器获取表格数据之后要做一步加工,遍历数据,加上item.saveButtonDisabled = false之类的语句,然后再赋值给data子对象。
  2. 给按钮绑定方法时,要传参数,element-ui中可以传row,也就是@click="clickSave(row)"。
  3. 点击按钮先验证数据,通过则立即row.saveButtonDisabled = true,ajax回调之后就row.saveButtonDisabled = false,就可以了。

情况2:点击之后不跳转,按钮也不消失

比如一个表单直接显示在网页中,无论提交多少次,页面都纹丝不动。

这时候再按照上面的情况的处理方案就行不通了,因为比如1秒数据就走了一个来回,那么我每1.1秒点击一次鼠标就可以无限提交下去。

处理方案:

首先,应该避免做这种“无论提交多少次,页面都纹丝不动”的设定,应该做到ajax返回OK之前,提交按钮是失效的,OK了就让提交按钮可点击,并且要弹个提示框,这个提示框就可以阻断连续提交。这里面还是有一个问题就是,如果在返回OK之后、提示框使用了Dialog,那么弹出的过程中点击了提交按钮,依然是可以提交的,因为还是那个动画问题,提示框弹出是需要时间的。这时候也好办,别用Dialog,用MessageBox就可以了,它有回调函数,在回调函数里让提交按钮可点击,就行了。

然后,如果有些场景下,必须“页面纹丝不动”,提示框都不允许有,那么这时候可以采用节流机制,也就是说按钮点击之后3秒内就不允许再点击,即便上一次的提交已经1秒完成。方案是:

点击之后验证,通过则立即不可点,不通过则不针对按钮处理

通过之后,设个变量resolve = 0,同时执行ajax以及setInterval(fn, 1000),由fn负责判断:

  1. 当ajax返回OK,则resolve += 1
  2. 当ajax返回错误,则resolve += 2
  3. 当延迟3秒,则resolve += 1
  4. 当resolve >= 2则让按钮可点,且clearInterval

这是一种比较奇葩的算法,也就是说,OK和3秒同时具备的话,resolve为2,则让按钮可点,只错误的话,resolve会等于或大于2,就立即让按钮可点,同时报错。

如果ajax超时,比如断网了,那么也会返回错误,只不过这个错误可能会10秒/20秒/30秒/60秒之后返回(根据你的ajax配置),其实这也属于上面说的ajax返回错误,所以依然是适用的。

情况3:点击之后跳转页面

点击之后跳转页面也很常见,无奈跳转页面也是需要时间的,也可以多次提交。怎么办?

  1. 页面打开时,让按钮可点(跟对话框场景道理一样)
  2. 点击之后验证,通过则立即不可点,不通过则不针对按钮处理
  3. 通过之后,当ajax返回OK,则立即跳转(不去恢复成可点),这样鼠标重复点击多少次都没事。当ajax返回错误,则弹出错误,且按钮恢复为可点

为什么当ajax返回错误后不防范重复点击?

因为我们将普通用户定义为:非常喜欢点击鼠标,但思维正常的人,既然用户已经看到了提示错误,当然就不会再重复点击了,况且错误提示往往会是MessageBox,它会阻止重复提交。我们更多的是考虑如何防范鼠标连击的情况。

恶意重复提交

前端永远是防君子,难防小人的,恶意攻击者想要恶意重复提交的话,一定会直接攻击后端,所以上面所有措施一律无效,还需要后端做措施,这里就不多说了。

最后说说axios拦截提交

根据网上一些教程,axios拦截提交其实是有问题的:

  • 它的拦截,其实是在重复提交的时候拦截前一次的提交,而我们通常认为,应该拦截后面发生的所有提交。
  • ajax速度有时候非常快,根本来不及拦截。
  • api写的太晦涩了。
  • 需要考虑多种情况,比如有的时候允许3秒提交一次,有的时候随时可以提交,拦截规则越搞越复杂。

利用URL和params特征判断是否能解决问题

比如,规定时间内(比如3秒),或者不设规定时间,只要向同一个URL发送同样的数据,就禁止发送。表面上看起来,似乎防范重复提交的本质就是要阻止同样的数据重复发送,但是这里面依然有问题。

比如规定时间3秒内不能发送同样数据,那么,如果是axios全局做判断,就要考虑,会不会有其他的ajax穿插在3秒里面,所以说,每次准备ajax发送请求,就要遍历追溯前三秒发送过的请求里有没有重复请求,所以始终要记录每一次请求,还要记下时间戳,似乎有些麻烦。如果只是根据每个提交事件做统计,其实道理一样,也是要遍历。

而且,如果用户每隔4秒点击一次,而ajax返回用时5秒,那么第二次请求就真的会发出去。

如果不规定时间,只要发送同样数据就一定拒绝,那么,如果用户不经意间,在3分钟内2次提交了相同的内容,允许不允许提交呢?比如用户3分钟中了2次奖,填了2次个人信息,允许提交吗?按说应该允许,因为有些场合确实可能存在用户提交同样内容,但是,现在禁止提交,就阻截了正常提交。最后只能是把拦截规则越搞越复杂。

当然,最为致命的问题是:用户体验莫名其妙。无论什么技术,都要把用户体验放在第一位,如果开发者不去管按钮能否点击,只做背后的拦截逻辑,也就是始终让按钮能点击,用户毫无疑问会有很大概率多次点击,如果赶上ajax慢,用户会疯狂点击,最后疯掉也不夸张,这不是我们想要的结果。

所以说前端拦截重复提交的最好办法一定是用正确逻辑控制按钮的disabled。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 写类方式之一
Jul 05 Javascript
Prototype 工具函数 学习
Jul 23 Javascript
用js写了一个类似php的print_r输出换行功能
Feb 18 Javascript
javascript实现实时输出当前的时间
Apr 27 Javascript
浅谈jQuery绑定事件会叠加的解决方法和心得总结
Oct 26 Javascript
headjs实现网站并行加载但顺序执行JS
Nov 29 Javascript
js实现的在线调色板功能完整实例
Dec 21 Javascript
vue2.0嵌套路由实现豆瓣电影分页功能(附demo)
Mar 13 Javascript
发布Angular应用至生产环境的方法
Dec 10 Javascript
微信小程序中转义字符的处理方法
Mar 28 Javascript
开发Node CLI构建微信小程序脚手架的示例
Mar 27 Javascript
微信小程序实现日历小功能
Nov 18 Javascript
js刷新页面location.reload()用法详解
Dec 09 #Javascript
vue 实现websocket发送消息并实时接收消息
Dec 09 #Javascript
Vue extend的基本用法(实例详解)
Dec 09 #Javascript
vue基于v-charts封装双向条形图的实现代码
Dec 09 #Javascript
微信小程序图片加载失败时替换为默认图片的方法
Dec 09 #Javascript
vue如何使用async、await实现同步请求
Dec 09 #Javascript
Vue替代marquee标签超出宽度文字横向滚动效果
Dec 09 #Javascript
You might like
PHP数据缓存技术
2007/02/14 PHP
drupal 代码实现URL重写
2011/05/04 PHP
php 安全过滤函数代码
2011/05/07 PHP
php脚本守护进程原理与实现方法详解
2017/07/20 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
Yii框架连表查询操作示例
2019/09/06 PHP
PHP7.3.10编译安装教程
2019/10/08 PHP
摘自启点的main.js
2008/04/20 Javascript
jQuery替换字符串(实例代码)
2013/11/13 Javascript
JQuery实现倒计时按钮具体方法
2013/11/14 Javascript
推荐8款jQuery轻量级树形Tree插件
2014/11/12 Javascript
javascript实现简单的贪吃蛇游戏
2015/03/31 Javascript
详解JavaScript基于面向对象之创建对象(1)
2015/12/10 Javascript
javascript中call apply 与 bind方法详解
2016/03/10 Javascript
JavaScript数组去重由慢到快由繁到简(优化篇)
2016/08/26 Javascript
微信小程序 rpx 尺寸单位详细介绍
2016/10/13 Javascript
vue实现学生录入系统之添加删除功能
2018/07/11 Javascript
angularjs性能优化的方法
2018/09/05 Javascript
js实现无刷新监听URL的变化示例代码详解
2020/06/03 Javascript
微信小程序点击生成朋友圈分享图(遇到的坑)
2020/06/17 Javascript
通过vue刷新左侧菜单栏操作
2020/08/06 Javascript
[01:00:44]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#1COL VS Alliance第三局
2016/03/04 DOTA
python使用urllib模块开发的多线程豆瓣小站mp3下载器
2014/01/16 Python
python函数局部变量用法实例分析
2015/08/04 Python
Python正则表达式知识汇总
2017/09/22 Python
Python cookbook(数据结构与算法)将名称映射到序列元素中的方法
2018/03/22 Python
python爬虫selenium和phantomJs使用方法解析
2019/08/08 Python
css3实现简单的白云飘动背景特效
2020/10/28 HTML / CSS
涂鸦板简单实现 Html5编写属于自己的画画板
2016/07/05 HTML / CSS
瑞典最好的运动鞋专卖店:Sneakersnstuff
2016/08/29 全球购物
美国护肤咨询及美容产品电商:Askderm
2017/02/24 全球购物
初三学生个人自我评定
2014/04/06 职场文书
法律专业求职信
2014/05/24 职场文书
党建目标管理责任书
2014/07/25 职场文书
师范生教育见习总结
2015/06/23 职场文书
信息简报范文
2015/07/21 职场文书