CSS是一門很神奇的語言,不少和它不相干的功能卻能起到很顯著的效果,有些在js看起來實現都有必定的工做量,CSS一句屬性就能垂手可得的解決,下面來看幾個例子(主要和js事件相關)。css
不少都是開腦洞想出來的,實現效果卻意外的驚人html
原issuesjquery
在js中對事件禁用並不複雜,可是卻容易影響到業務邏輯git
function buy(){
if(XX){
return false;
}
//其餘業務代碼
}
複製代碼
固然,元素也要設置相應的樣式,讓它看起來不可點擊。github
css對事件禁用就比較簡單了,主要有兩種方式工具
1. disabled動畫
原生表單元素是有默認的禁用屬性的,好比ui
<button disabled onclick="alert(11)">按鈕</button>
複製代碼
能夠看出,禁用的默認樣式爲this
button:disabled {
color: graytext;
}
複製代碼
因此,在這裏你能夠隨意的修改禁用的樣式
button:disabled {
color: red;
}
button[disabled] {/**屬性選擇器也行**/
color: red;
}
button:hover { /**:hover支持**/
color: red;
}
button:active,button:focus{/**不支持,其實也好理解,會觸發focus()事件,因此也禁用了**/
color:red
}
複製代碼
通常狀況下,使用這種方式是比較好的,自然的禁用屬性,兼容性也不錯
2. pointer-events:none
這個屬性應該也不陌生,最多見的用法就是禁用一個按鈕,並且不侷限於表單元素,任意元素都可(好比不少人喜歡用的a標籤)
button.disabled {
pointer-events:none;
user-select:none;/*去除選中效果*/
color: graytext;
}
複製代碼
這個屬性用處不少,不少js絞盡腦汁想要過濾掉的方法,直接就用一行屬性解決,這裏就不展開了,網上教程不少。
See the Pen css 禁用事件 by XboxYan ( @xboxyan) on CodePen.原生js中並無長按事件,一般開發者通常會順着思路,使用定時器來完成
下面是僞代碼
el.onmousedown = function(){
this.timer && clearTimeout(this.timer);
this.timer = settimeout(function(){
//業務代碼
},350)
}
el.onmouseup = function(){
this.timer && clearTimeout(this.timer);
}
複製代碼
固然,能夠藉助css來完成,並且效果更好,易於控制
這裏爲何說是「藉助」呢,由於不能徹底有css來完成,只是利用了某些特性
css3中新增了過渡和動畫屬性,與之相對應的也預設了這些動畫的回調事件,以下
事件 | 說明 |
---|---|
transitionstart |
在開始過渡時觸發 |
transitionrun |
在進行過渡時觸發 |
transitioncancel |
在取消過渡時觸發 |
transitionend |
在完成過渡後觸發 |
animationstart |
在 animation 開始時觸發 |
animationiteration |
在 animation 完成一個週期時觸發 |
animationend |
在 animation 完成時觸發 |
animationcancel |
在 animation 取消時觸發 |
有些事件存在兼容性問題,有興趣的能夠詳細研究
有了這些事件,要作一個長按事件就很容易了,這裏有兩種種思路,你們能夠腦洞一下
假設須要延時1s;
transitionend
或者animationend
transitionstart
或者animationstart
這裏以第一種狀況transitionend
(過渡比動畫實現要容易多,代碼也少,優先用過渡)來實現
button:hover:active{
opacity:.99;/**隨便選取一個不影響頁面的能夠過渡的樣式**/
transition:opacity 1s;
}
複製代碼
相應的,js須要監聽transitionend
事件,不須要藉助定時器(我的有點鄙視定時器的思想^)
el.addEventListener('transitionend',function(){
//業務代碼
})
複製代碼
是否是精簡不少呢,須要改長按時間能夠直接經過css來控制
這裏封裝了一下自定義事件,能夠更好的在項目中使用(雖然代碼自己就不多了)。
See the Pen css 長按事件 by XboxYan ( @xboxyan) on CodePen.在jquery
中有一個once
(好像是這個)方法,表示綁定一次性事件,點擊一次後就再也不生效。
原生js實現這個也不復雜,一般作法就是定義一個標識,點擊後改變一下,下面是僞代碼
el.onclick = function(){
if(!this.once){
//業務代碼
this.once = true;
}
}
複製代碼
藉助上面的思路,css也能夠實現相似的效果,深究了一番,總結如下兩個方法
animationend
是動畫結束後觸發,顯然咱們能夠在這裏作文章
好比咱們能夠在初始狀態給一個暫停狀態animation-play-state:paused
,而後在點擊時運動animation-play-state:running
,結束後一直保持在最後狀態animation-fill-mode: forwards
.button{
animation: once .01s paused forwards;/**給一個足夠小的運動時間,確保可以在`:active`時運動完成**/
}
.button:hover:active{
animation-play-state:running;
}
@keyframes once {
to{
opacity:.8;
}
}
複製代碼
js只須要對animationend
進行監聽
el.addEventListener('animationend',function(){
//業務代碼
})
複製代碼
不知道在上面的例子中有沒有發現,在動畫結束時把元素禁用會怎麼樣?
@keyframes once {
to{
opacity:.8;
pointer-events:none;
user-select:none;
}
}
複製代碼
<button class="button" onclick="fn()">按鈕</button>
複製代碼
這樣就能夠在運動完直接禁用,好像很完美?
事實上,這裏運動的時間很難把控,你們都知道,onclick
實際上是包含按下和擡起兩個過程的,若是擡起的太慢,那麼此時元素已經禁用了,觸發不了事件;若是擡起太快,若是快速點擊,因爲還沒運動完成,會觸發屢次事件。
解決方式也很簡單,用onmousedown
代替便可
<button class="button" onmousedown="fn()">按鈕</button>
複製代碼
See the Pen
css 單次事件 by XboxYan (
@xboxyan) on
CodePen.
你們都知道window
有個onresize
事件,能夠在窗口拉伸的時候觸發,而後就能實時獲取窗體的尺寸等等屬性。
window.onresize = function(ev){
//業務代碼
}
複製代碼
可是,普通的元素卻沒有這個監聽,好比
div.onresize = function(ev){
//不生效...
}
複製代碼
爲何須要這個功能呢?
你們可能知道有這樣一個屬性,能夠原生拉伸元素,改變尺寸
.box{
overflow: hidden;/**須要配合overflow才能生效**/
resize: both;
}
複製代碼
只需一個屬性,就能夠實現元素的拉伸(雖然稍有瑕疵),不須要大量的js來計算。
視覺展現還好,可是若是須要實時知道元素的尺寸怎麼辦呢,js一般有兩種思路
1. onmousemove事件
拉伸的時候很天然的想到是有鼠標按住而後拖拽完成,因此能夠給元素添加onmouse-*
一系列事件,同時要注意鼠標擡起要取消監聽
//大概是這樣的邏輯
div.onmousedown = function(){
div.onmousemove = fn;//監聽
div.onmouseup = function(){
div.onmousemove = null;
}
}
複製代碼
2. 定時器
藉助setInterval
或者requestAnimFrame
來實現監聽,一樣是須要注意取消監聽的時機
//大概是這樣的邏輯
div.onmousedown = function(){
this.timer && clearInterval(this.timer)
this.timer = setInterval(fn,300);//監聽
div.onmouseup = function(){
this.timer && clearInterval(this.timer)
}
}
複製代碼
很顯然,上面的方法都不是特別的溫馨,不少狀況下都會出現監聽取消的問題,致使不停的觸發,影響體驗。
這時候,又輪到css出場了,不少時候js以爲實現起來不暢的時候均可以用css的思惟來從新認識。
那麼,如何藉助css來監聽這些呢?
能夠從過渡和動畫兩個思路來考慮。
1. CSS過渡
首先,咱們能夠知道的是,在經過resize: both
進行元素拉伸的時候,改變的是width
和height
,這一點能夠從開發者工具直接看到
咱們須要經過transitionrun
或者transitionend
來監聽width
和height
,因此須要給這兩個屬性加上過渡
.box{
transition:width .3s,ehight .3s;//分別給width和height設置過渡,其餘屬性不須要
}
複製代碼
這樣就能夠拿到監聽了,不過這種方式有一個弊端,因爲過渡須要時間,因此有一種不跟隨,卡頓的感受。
因此咱們來看第二種方式
2. animationiteration
css
動畫能夠設置播放次數,若是設置成animation-iteration-count: infinite
就表示無限輪播,配合animationiteration
回調,不就能夠實現監聽了麼
.box:active{
animation: resize .3s infinite forwards;
}
@keyframes resize{
to {
opacity: .99;/**用一個可有可無的屬性來觸發動畫**/
}
}
複製代碼
js很簡單,一個監聽就能解決問題,也不須要什麼取消監聽什麼,這些都已經在css完成了
el.addEventListener('animationiteration',function(){
//業務代碼
})
複製代碼
這裏是每一個動畫完成一次就回調一次,因此咱們能夠經過設置動畫時長來控制監聽的頻率,好比上面是.3s
的觸發頻率。
下面寫了一個demo,能夠實現自定義onresize
事件
以上經過藉助css,實現了許多js都很棘手的問題,可能還會有更多的應用場景,歡迎小夥伴留言討論~