整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

a标签和button按钮只允许点击一次,防止重复提交

a标签和button按钮只允许点击一次,防止重复提交

utton

方法:加上属性disabled=“disabled” 或者 disabled=“true”

<button id="btn" disabled="disabled">确定</button>
2>Javascript里
<script>
 $("#btn").attr("disabled","true");
 $("#btn").attr("disabled","disabled");
 $("#btn").attr("disabled","false");
 $("#btn").removeAttr("disabled","disabled");
</script>

a标签

方法:在点击一次后,解除绑定。

<a id="mybtn">button</a>
<script>
 $("a").click(function(){
 alert("1");
 $(this).css("color","#CCC");
 $(this).unbind("click");
 })
</script>

或者:

常开发中经常会用到表单提交,如果表单没有做防重复提交,可能会引起系统业务逻辑异常,导致系统数据错乱

下面我给出一套常用的解决方案,前端用javascript锁防止重复点击,后端验证session里面的token值防止重复提交

一、引起表单重复提交有以下几种常见场景

  • 重复点击提交按钮。包括恶意的连续点击提交按钮,或因为网络慢、服务器处理速度慢等引起的用户多次点击
  • 表单提交处理完后,通过浏览器的后退按钮回到原页面再次点击提交按钮
  • 通过点击浏览器的刷新按钮,导致表单重复提交
  • 通过浏览器的历史记录,获取表单提交的URL地址,再次访问

二、前端

session中设置一个token

String token=UUID.randomUUID().toString();
session.setAttribute("formToken", token);

表单html

<html>
<head>
<title>员工信息</title>
</head>
<body>
  <form method="post" action="/postForm">
    姓名:<input type="text" name="userName">
    年龄:<input type="text" name="age">
    性别:<input type="text" name="sex">
    <input type="hidden" name="formToken" value="${formToken}">
    <input type="button" value="保存" onclick="infoSave()">
  </form>
</body>
</html>

js防止重复点击

<script>
var isSaving=false;
function infoSave() {
    if(isSaving) {
   		 return false;
    }
    isSaving=true;
    Ajax.post('https://xxx.xxx.xxx/infoSave',params).then(function(res){
      isSaving=false;
      if(res.code==200){
      	alert("修改成功");
      }else{
      	alert(res.message);
      }
      window.location.reload();
    });
}
</script>

三、服务端

String Token1=request.getParameter("formToken");
String Token2=(String) session.getAttribute("formToken");
if (Token1 !=null && Token1.equals(Token2)) {
  // 处理表单提交 ...
  // 删除标识符
  session.removeAttribute("formToken");
}else{
	// 重复提交,给出错误提示
} 

四、总结

一般情况下采用JS脚本方式和服务端方式两种结合已可防止表单重复提交,针对特殊业务要求的可采用数据库唯一性约束限制等方式来强制保证业务逻辑上的数据唯一要求。

所周知,函数节流(throttle)是 JS 中一个非常常见的优化手段,可以有效的避免函数过于频繁的执行。

举个例子:一个保存按钮,为了避免重复提交或者服务器考虑,往往需要对点击行为做一定的限制,比如只允许每300ms提交一次,这时候我想大部分同学都会到网上直接拷贝一段throttle函数,或者直接引用lodash工具库

btn.addEventListener('click', _.throttle(save, 300))

其实除了 JS 方式, CSS 也可以非常轻易的实现这样一个功能,无需任何框架库,一起看看吧

一、CSS 实现思路分析

CSS 实现和 JS 的思维不同,需要从另一个角度去看待这个问题。

比如这里的需要对点击事件进行限制,也就是禁用点击事件,想想有什么方式可以禁用事件,没错,就是pointer-events;

然后是时间的限制,每次点击后需要自动禁用300ms,时间过后重新恢复,那么,有什么特性和时间以及状态恢复有关呢?没错,就是animation;

除此之外,还需要有触发时机,这里是点击行为,所以必然和伪类:active有关联。

因此,综合分析,实现这样一个功能需要用到pointer-events、animation以及:active,那么如何将这些思路串联起来呢?

思考3秒...

你想到了吗?

其实这种场景可以理解成是对 CSS 动画的控制,比如有一个动画控制按钮从禁用->可点击的变化,每次点击时让这个动画重新执行一遍,在执行的过程中,一直处于禁用状态,是不是就达到了“节流”的效果了?

接下来看看具体实现

二、CSS 动画的精准控制

假设有一个按钮,绑定了一个点击事件

<button onclick="console.log('保存')">保存</button>

这时的按钮连续点击就会不断地触发,效果如下

下面定义一个关于pointer-events的动画,就叫做 throttle

@keyframes throttle {
  from {
    pointer-events: none;
  }
  to {
    pointer-events: all;
  }
}

很简单吧,就是从禁用可点击的变化。

接下来,将这个动画绑定在按钮上,这里为了方便测试,将动画设置成了2s

button{
  animation: throttle 2s step-end forwards;
}

注意,这里动画的缓动函数设置成了阶梯曲线,step-end,它可以很方便的控制pointer-events的变化时间点。

如下示意,pointer-events在0~2秒内的值都是none,一旦到达2秒,就立刻变成了all,由于是forwards,会一直保持all的状态

最后,在点击时重新执行一遍动画,只需要在按下时设置动画为none就行了

这个技巧之前在这篇文章中有更详细的介绍: CSS 实现按钮点击动效的套路

实现如下

button:active{
  animation: none;
}

为了演示方便,我们暂时把颜色变化也加在动画里

@keyframes throttle {
  from {
    color: red;
    pointer-events: none;
  }
  to {
    color: green;
    pointer-events: all;
  }
}

现在如果文字是red,表示是禁用态,只有是green,才表示可以被点击,非常清晰明了,如下

下面是最终点击对比效果,很好地限制了点击频率

完整代码如下,就这么几行,如果需要改限制时间,直接改动画时间就行了

button{
  animation: throttle 2s step-end forwards;
}
button:active{
  animation: none;
}
@keyframes throttle {
  from {
    pointer-events: none;
  }
  to {
    pointer-events: all;
  }
}

三、CSS 实现的其他思路

借用这种思路,也可以很轻松的实现节流的效果。而且为了更好的体验,可以用上真正的按钮禁用

btn.disabled=true

具体思路是这样的,通过:active去触发transition变化,然后通过监听transition回调去动态设置按钮的禁用状态,实现如下

定义一个无关紧要的过渡属性,比如opacity

button{
  opacity: .99;
  transition: opacity 2s;
}
button:not(:disabled):active{
  opacity: 1;
  transition: 0s;
}

然后监听transition的起始回调

// 过渡开始
document.addEventListener('transitionstart', function(ev){
  ev.target.disabled=true
})
// 过渡结束
document.addEventListener('transitionend', function(ev){
  ev.target.disabled=false
})

这样做的最大好处是,这部分禁用的逻辑是完全和业务逻辑是解耦的,可以在任意时候,任意场合下无缝接入,也不受框架和环境影响,效果如下

四、总结一下

以上通过 CSS 的思路实现了类似“节流”的功能,相比 JS 实现而言,实现更精简、使用更简单,没有框架限制,下面一起总结一下实现要点:

  1. 函数节流是一个非常常见的优化方式,可以有效避免函数过于频繁的执行
  2. CSS 的实现思路和 JS 不同,重点在于在于找到和该场景相关联的属性
  3. CSS 实现“节流”其实就是控制一个动画的精准控制,假设有一个动画控制按钮从禁用->可点击的变化,每次点击时让这个动画重新执行一遍,在执行的过程中,一直处于禁用状态,这样就达到了“节流”的效果
  4. 还可以通过 transition 的回调函数动态设置按钮禁用态
  5. 这种实现的好处在于禁用逻辑和业务逻辑是完全解耦的



原文链接:https://juejin.cn/post/7165828047520661534