当前位置: 首页 > 科技观察

你还在用定时器吗?使用CSS监听事件

时间:2023-03-14 12:46:01 科技观察

平时工作中很多场合都会用到定时器,比如延迟加载,定时查询等,但是定时器的控制有时候会有点麻烦,比如鼠标移动停止,移动退出并重新启动。这次,我将介绍几种借助CSS更好地控制定时器的方法。让我们一起了解它。相信能带来不一样的体验。1、悬停延时触发器有这样一种场景,鼠标在元素上停留1s后才触发事件,小于1s则不会触发。这样做的好处是可以避免鼠标滑过时频繁触发事件。如果用js实现的话,可能是这样的。vartimer=nullel.addEventListener('mouseover',()=>{timer&&clearTimeout(timer)timer=setTimeout(()=>{//具体逻辑},1000)})这样对吗?等等,这还没完,这只是实现了一个延时,鼠标离开后还是会触发,需要在鼠标离开时取消定时器。el.addEventListener('mouseout',()=>{timer&&clearTimeout(timer)})另外,在使用mouseout的时候,还需要考虑dom的嵌套结构,因为这些事件都在父进程中——>child还是会被触发。总之细节会很大,很容易误触发。现在转折点来了。如果借用CSS,就可以有效避免以上问题。如下,先给需要触发的元素添加一个带有延时的transition。按钮:悬停{不透明度:0.999;/*无关紧要的风格*/transition:0s1sopacity;/*Delay1s*/}这里只需要一个无关紧要的样式,如果已经使用了opacity,可以使用其他的,比如transform:translateZ(.1px),也是可以的。然后添加侦听器transitionend方法。GlobalEventHandlers.ontransitionend-WebAPI接口参考|MDN(mozilla.org)[1]。el.addEventListener('transitionend',()=>{//具体逻辑})到此结束。无定时器,无取消,无需考虑dom结构,完美实现。下面是一个在悬停一段时间后触发警报的小示例。Kapture2022-09-11at15.56.37原理同上。完整代码可以查看在线demo:hover_alert(codepen.io)[2]或hover_alert(runjs.work)[3]。如果以后遇到这样的需求,可以停下来想一想。很多mouseover相关的交互都可以通过这种方式实现。2、长按触发事件长按也是比较常见的需求,可以很好的和点击事件区分开来,从而赋予更多的交互能力。但是原生js中是没有这个事件的。如果要实现长按事件,通常需要使用定时器和鼠标按下事件,如下:el.onmousedown=function(){this.timer&&clearTimeout(this.timer);this.timer=settimeout(function(){//业务代码},1000)}el.onmouseup=function(){this.timer&&clearTimeout(this.timer);}是定时器和取消定时器的场景前面的例子有点类似,也可以借助CSS来实现。由于鼠标按下,可以关联:active,所以可以这样实现。按钮:悬停:活动{不透明度:.999;/*不相关的样式*/transition:opacity1s;/*delay1s*/}然后监听transitionend方法;el.addEventListener('transitionend',()=>{//具体逻辑})是不是很方便?下面是之前做过的一个小case,实现长按触发元素选择。Kapture2022-09-13at10.37.01完整代码可以查看在线演示:长按方框(codepen.io)[4]或长按方框(runjs.work)[5]。3.轮播和暂停让我们看一个更有趣的例子,轮播图。通常轮播会自动播放,然后鼠标悬停时轮播会暂停,这是通常的做法。functionautoPlay(){timer&&clearInterval(timer)timer=setInterval(function(){//轮播逻辑},1000)}autoPlay()view.onmouseover=function(){timer&&clearInterval(timer)}el.onmouseout=function(){autoPlay()}是定时器的取消和设置。绑定一堆事件太烦人了。你能改变它吗?当然可以,多亏了CSS动画,一切都很容易处理。和上一个不同的是这里是setInterval,可以重复触发,那么css中有什么可以重复触发的呢?没错,CSS动画!当CSS动画设置为infinite时,可以无限循环,和这个timer效果很像,可以直接通过:hover暂停播放动画。要监听每个动画的触发情况,可以使用animationiteration方法,即每个动画循环触发一次。GlobalEventHandlers.onanimationiteration-WebAPI接口参考|MDN(mozilla.org)[6]。所以这个想法的实现是;.view{动画:无限滚动1s;/*每1s动画一次,无限循环*/}.view:hover{animation-play-state:paused;/*悬停暂停*/}@keyframesscroll{to{transform:translateZ(.1px);/*无关样式*/}}然后监听动画迭代事件;view.addEventListener("animationiteration",()=>{//旋转逻辑})是不是省去了大部分的js代码?它也更容易理解和控制。下面是用animationiteration代替setInterval实现的轮播图。Kapture2022-09-11at16.43.49完整代码可以在在线演示中查看:CSSbanner(codepen.io)[7]或css_banner(runjs.work)[8]。4.综上所述,以上就是几种你可能不需要定时器的方案。与定时器相比,CSS在控制定时器的开启和暂停方面更有优势。这里总结一下::hoverwithtransitiondelay时间,transitionend监听可以实现鼠标延迟触发的效果。:active配合transitiondelay和transitionend监听实现长按触发效果。CSS动画设置为无限后,结合动画迭代监控,可以实现周期性的触发效果。您可以直接通过:hover暂停和播放控制台动画。当然,不仅可以使用上述案例,任何具有类似功能的CSS交互(:hover,:active)都可以往这个方向考虑。可以更优雅地实现吗?