藉助CSS來管理js事件

CSS是一門很神奇的語言,不少和它不相干的功能卻能起到很顯著的效果,有些在js看起來實現都有必定的工做量,CSS一句屬性就能垂手可得的解決,下面來看幾個例子(主要和js事件相關)。css

原連接html

https://notes.codelabo.cn/art...jquery

原issuescss3

https://github.com/XboxYan/no...git

不少都是開腦洞想出來的,實現效果卻意外的驚人

事件禁用

在js中對事件禁用並不複雜,可是卻容易影響到業務邏輯github

function buy(){
  if(XX){
    return false;
  }
  //其餘業務代碼
}

固然,元素也要設置相應的樣式,讓它看起來不可點擊。工具

css對事件禁用就比較簡單了,主要有兩種方式動畫

1. disabledthis

原生表單元素是有默認的禁用屬性的,好比spa

<button disabled onclick="alert(11)">按鈕</button>

image

能夠看出,禁用的默認樣式爲

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絞盡腦汁想要過濾掉的方法,直接就用一行屬性解決,這裏就不展開了,網上教程不少。

查看這個demo

<iframe height="300" style="width: 100%;" scrolling="no" title="css 禁用事件" src="//codepen.io/xboxyan/embed/KLGXjR/?height=300&theme-id=34022&default-tab=html,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen css 禁用事件 by XboxYan
(@xboxyan) on CodePen.
</iframe>

長按事件

原生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;

  1. 過渡時間設置爲1s,調用transitionend或者animationend
  2. 延時1s,調用transitionstart或者animationstart

這裏以第一種狀況transitionend(過渡比動畫實現要容易多,代碼也少,優先用過渡)來實現

button:hover:active{
  opacity:.99;/**隨便選取一個不影響頁面的能夠過渡的樣式**/
  transition:opacity 1s;
}

相應的,js須要監聽transitionend事件,不須要藉助定時器(我的有點鄙視定時器的思想^)

el.addEventListener('transitionend',function(){
    //業務代碼
})

是否是精簡不少呢,須要改長按時間能夠直接經過css來控制

這裏封裝了一下自定義事件,能夠更好的在項目中使用(雖然代碼自己就不多了)。

image

查看這個demo

<iframe height="300" style="width: 100%;" scrolling="no" title="css 長按事件" src="//codepen.io/xboxyan/embed/KLxXNZ/?height=300&theme-id=34022&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen css 長按事件 by XboxYan
(@xboxyan) on CodePen.
</iframe>

單次點擊事件

jquery中有一個once(好像是這個)方法,表示綁定一次性事件,點擊一次後就再也不生效。

原生js實現這個也不復雜,一般作法就是定義一個標識,點擊後改變一下,下面是僞代碼

el.onclick = function(){
   if(!this.once){
       //業務代碼
       this.once = true;
   }
}

藉助上面的思路,css也能夠實現相似的效果,深究了一番,總結如下兩個方法

1.animationend

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(){
    //業務代碼
})

2.純css實現

不知道在上面的例子中有沒有發現,在動畫結束時把元素禁用會怎麼樣?

@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>

image

查看這個demo

<iframe height="300" style="width: 100%;" scrolling="no" title="css 單次事件" src="//codepen.io/xboxyan/embed/ZNqrbX/?height=300&theme-id=34022&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen css 單次事件 by XboxYan
(@xboxyan) on CodePen.
</iframe>

onresize事件

你們都知道window有個onresize事件,能夠在窗口拉伸的時候觸發,而後就能實時獲取窗體的尺寸等等屬性。

window.onresize = function(ev){
   //業務代碼
}

可是,普通的元素卻沒有這個監聽,好比

div.onresize = function(ev){
   //不生效...
}

爲何須要這個功能呢?

你們可能知道有這樣一個屬性,能夠原生拉伸元素,改變尺寸

.box{
    overflow: hidden;/**須要配合overflow才能生效**/
    resize: both;
}

resize

只需一個屬性,就能夠實現元素的拉伸(雖然稍有瑕疵),不須要大量的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進行元素拉伸的時候,改變的是widthheight,這一點能夠從開發者工具直接看到

resize_1

咱們須要經過transitionrun或者transitionend來監聽widthheight,因此須要給這兩個屬性加上過渡

.box{
   transition:width .3s,ehight .3s;//分別給width和height設置過渡,其餘屬性不須要
}

這樣就能夠拿到監聽了,不過這種方式有一個弊端,因爲過渡須要時間,因此有一種不跟隨,卡頓的感受。

resize_2

因此咱們來看第二種方式

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事件

resize_3

查看這個demo

<iframe height="300" style="width: 100%;" scrolling="no" title="css resize事件" src="//codepen.io/xboxyan/embed/PvyeOL/?height=300&theme-id=34022&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen css resize事件 by XboxYan
(@xboxyan) on CodePen.
</iframe>

小節

以上經過藉助css,實現了許多js都很棘手的問題,可能還會有更多的應用場景,歡迎小夥伴留言討論~

若是有新的想法,會第一時間更新在 https://github.com/XboxYan/no... ,多多關注

相關文章
相關標籤/搜索