歡迎關注我的公眾號:前端偵探
平時工作中很多場合都要用到定時器,比如延遲載入、定時查詢等等,但定時器的控制有時候會有些許麻煩,比如滑鼠移入停止、移出再重新開始。這次介紹幾個藉助 CSS 來更好的控制定時器的方法,一起了解一下吧,相信可以帶來不一樣的體驗
一、hover 延時觸發
有這樣一個場景,在滑鼠停留在一個元素上1s
後才觸發事件,不滿1s
就不會觸發,這樣的好處是,可以避免滑鼠在快速劃過時,頻繁的觸發事件。如果是用js
來實現,可能會這樣
var timer = null
el.addEventListener('mouseover', () => {
timer && clearTimeout(timer)
timer = setTimeout(() => {
// 具體邏輯
}, 1000)
})
是不是這樣?等等,這樣還沒完,這樣只做到了延時,滑鼠離開以後還是會觸發,還需要在滑鼠離開時取消定時器
el.addEventListener('mouseout', () => {
timer && clearTimeout(timer)
})
另外,在使用mouseout
時還需要考慮 dom
巢狀結構,因為這些事件在父級 -> 子級
的過程中仍然會觸發,總之,細節會非常多,很容易誤觸發。
現在轉折來了,如果借用 CSS 就可以有效地避免上述問題,如下,先給需要觸發的元素加一個有延時的transition
button:hover{
opacity: 0.999; /*無關緊要的樣式*/
transition: 0s 1s opacity; /*延時 1s */
}
這裡只需一個無關緊要的樣式就行,如果opacity
已經使用過了,可以使用其他的,比如transform:translateZ(.1px)
,也是可行的。然後新增監聽transitionend
方法
GlobalEventHandlers.ontransitionend - Web API 介面參考 | MDN (mozilla.org)
el.addEventListener('transitionend', () => {
// 具體邏輯
})
這就結束了。無需定時器,也無需取消,更無需考慮 dom
結構,完美實現。
下面是一個小例項,在hover
一段時間後觸發alert
原理和上面一致,完整程式碼可以檢視線上demo:hover_alert(runjs.work)
?以後再碰到這樣的需要可以停下來思考一番,很多和mouseover
有關的互動都可以用這種方式來實現
二、長按觸發事件
長按也是一個比較常見的需求,它可以很好的和點選事件區分開來,從而賦予更多的互動能力。
但是原生js
中卻沒有這樣一個事件,如果要實現長按事件,通常需要藉助定時器和滑鼠按下事件,如下
el.onmousedown = function(){
this.timer && clearTimeout(this.timer);
this.timer = settimeout(function(){
//業務程式碼
},1000)
}
el.onmouseup = function(){
this.timer && clearTimeout(this.timer);
}
又是定時器和取消定時器的場景,和前面一個例子有些類似,也可以藉助 CSS 來實現,由於是滑鼠按下,可以聯想到:active
,因此可以這樣來實現
button:hover:active{
opacity: .999; /*無關緊要的樣式*/
transition: opacity 1s; /*延時 1s */
}
然後再監聽transitionend
方法
el.addEventListener('transitionend', () => {
// 具體邏輯
})
是不是非常方便呢?下面是以前做過的一個小案例,實現了長按觸發元素選中
完整程式碼可以檢視線上demo:長按框選 (runjs.work)
三、輪播和暫停
再來看一個比較有意思的例子,輪播圖。
通常輪播圖都會自動播放,然後滑鼠hover
時會暫停輪播圖,通常的做法是這樣的
function autoPlay(){
timer && clearInterval(timer)
timer = setInterval(function(){
// 輪播邏輯
}, 1000)
}
autoPlay()
view.onmouseover = function(){
timer && clearInterval(timer)
}
el.onmouseout = function(){
autoPlay()
}
又是定時器的取消和設定,要繫結一堆事件,太煩人了,可以換種方式嗎?當然可以了,藉助 CSS 動畫,一切都好辦了。
和前面不太相同的是,這裡是setInterval
,可以重複觸發,那 CSS 中有什麼可以重複觸發的呢?沒錯,就是 CSS 動畫!
當 CSS 動畫設定次數為infinite
就可以無限迴圈了,和這個定時器效果非常類似,而且可以直接透過:hover
暫停和播放動畫。監聽每次動畫的觸發可以用animationiteration
這個方法,表示每個動畫輪迴就觸發一次
GlobalEventHandlers.onanimationiteration - Web API 介面參考 | MDN (mozilla.org)
所以用這種思路實現就是
.view {
animation: scroll 1s infinite; /*每1s動畫,無限迴圈*/
}
.view:hover{
animation-play-state: paused; /*hover暫停*/
}
@keyframes scroll {
to {
transform: translateZ(.1px); /*無關緊要的樣式*/
}
}
然後再監聽animationiteration
事件
view.addEventListener("animationiteration", () => {
// 輪播邏輯
})
是不是省去了大半的js
程式碼?而且也更好理解,控制也更為方便。
下面是一個透過animationiteration
來代替setInterval
實現的輪播圖
完整程式碼可以檢視線上demo:css_banner(runjs.work)
四、總結一下
以上就是你可能不需要定時器的幾個替代方案,相比定時器而言,CSS 在控制定時器的開啟和暫停上更有優勢,下面總結一下
:hover
配合transition
延時、transitionend
監聽可以實現滑鼠經過延時觸發效果:active
配合transition
延時、transitionend
監聽可以實現長按觸發效果- CSS 動畫設定
infinite
後配合animationiteration
監聽可以實現週期性觸發效果 - 可以直接透過
:hover
來控制檯動畫的暫停和播放
當然,可以利用的不僅僅是以上幾個案例,任何和 CSS 互動(:hover
、:active
)有類似功能的都可以朝這個方向去思考,是不是可以實現地更加優雅??
最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤
歡迎關注我的公眾號:前端偵探