头图

还在用 JS 做节流吗?CSS 也可以防止按钮重复点击

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

欢迎关注我的公众号:前端侦探

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

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

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

一、CSS 实现思路分析

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

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

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

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

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

image.png

思考3秒...

🤔

🤔

🤔

你想到了吗?💡💡💡

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

接下来看看具体实现

二、CSS 动画的精准控制

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

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

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

Kapture 2022-11-12 at 00.17.44.gif

下面定义一个关于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的变化时间点。

有兴趣的可以参考这篇文章:CSS3 animation属性中的steps功能符深入介绍 « 张鑫旭-鑫空间-鑫生活 (zhangxinxu.com)

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

image.png

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

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

实现如下

button:active{
  animation: none;
}

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

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

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

Kapture 2022-11-12 at 10.54.43.gif

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

Kapture 2022-11-12 at 10.48.13.gif

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

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

你也可以查看以下任意链接:

三、CSS 实现的其他思路

还记得之前这一篇文章吗?

还在用定时器吗?借助 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
})

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

Kapture 2022-11-14 at 17.25.49

完整代码也可以查看以下任意链接:

四、总结一下

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

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

不过,这种实现方式还是比较有局限的,仅限于点击行为,像很多时候,节流可能会用在滚动事件或者键盘事件上,像这些场景就用传统方式实现就行了。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

欢迎关注我的公众号:前端侦探

前端侦探
致力于有趣的前端探索~
14.6k 声望
13.7k 粉丝
0 条评论
推荐阅读
原生popover终于来了!
欢迎关注我的公众号:前端侦探提到 popover,相信大家都很熟悉,没错,就是组件库里经常见到的悬浮层(或者叫“气泡卡片”),比如 Ant Design现在,这个好用的特性终于在Chrome 114上正式支持了~下面花几分钟快速...

XboxYan5阅读 352

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco20阅读 2.1k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
你可能不需要JS!CSS实现一个计时器
CSS现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?样式上并不复杂,主要是几个交互的地方数字时钟的变化开始、暂停操作重置操作如何仅使用 CSS 来实现这样的功能呢?一起...

XboxYan21阅读 1.6k评论 1

封面图
「彻底弄懂」this全面解析
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在 哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this就是记录的其中一个属性,会在 函数执行的过程中用到...

wuwhs17阅读 2.4k

封面图
学会这些 Web API 使你的开发效率翻倍
随着浏览器的日益壮大,浏览器自带的功能也随着增多,在 Web 开发过程中,我们经常会使用一些 Web API 增加我们的开发效率。本篇文章主要选取了一些有趣且有用的 Web API 进行介绍,并且 API 可以在线运行预览。C...

九旬13阅读 1.5k

封面图
14.6k 声望
13.7k 粉丝
宣传栏