借助CSS来管理js事件

简介: 借助CSS来管理js事件

CSS是一门很神奇的语言,很多和它不相干的功能却能起到很显著的效果,有些在js看起来实现都有一定的工作量,CSS一句属性就能轻而易举的解决,下面来看几个例子(主要和js事件相关)。


原链接

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


原issues

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


很多都是开脑洞想出来的,实现效果却意外的惊人


事件禁用


在js中对事件禁用并不复杂,但是却容易影响到业务逻辑

function buy(){
  if(XX){
    return false;
  }
  //其他业务代码
}


当然,元素也要设置相应的样式,让它看起来不可点击。


css对事件禁用就比较简单了,主要有两种方式


1. disabled


原生表单元素是有默认的禁用属性的,比如

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

image.png

可以看出,禁用的默认样式为

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.png

查看这个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.png

查看这个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;
}

image.png

只需一个属性,就可以实现元素的拉伸(虽然稍有瑕疵),不需要大量的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,这一点可以从开发者工具直接看到


image.png

我们需要通过transitionrun或者transitionend来监听widthheight,所以需要给这两个属性加上过渡

.box{
   transition:width .3s,ehight .3s;//分别给width和height设置过渡,其他属性不需要
}


这样就可以拿到监听了,不过这种方式有一个弊端,由于过渡需要时间,所以有一种不跟随,卡顿的感觉。

image.png

所以我们来看第二种方式


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

image.png


查看这个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... ,多多关注

相关文章
|
16天前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
1月前
|
Web App开发 JavaScript 前端开发
javascript onkeydown事件
javascript onkeydown事件
|
1月前
|
JavaScript
js两种移除事件的方法
js两种移除事件的方法
30 2
|
4天前
|
前端开发 JavaScript
如何在 JavaScript 中访问和修改 CSS 变量?
【10月更文挑战第28天】通过以上方法,可以在JavaScript中灵活地访问和修改CSS变量,从而实现根据用户交互、页面状态等动态地改变页面样式,为网页添加更多的交互性和动态效果。在实际应用中,可以根据具体的需求和场景选择合适的方法来操作CSS变量。
|
4天前
|
前端开发 JavaScript UED
如何使用 JavaScript 动态修改 CSS 变量的值?
【10月更文挑战第28天】使用JavaScript动态修改CSS变量的值可以为页面带来更丰富的交互效果和动态样式变化,根据不同的应用场景和需求,可以选择合适的方法来实现CSS变量的动态修改,从而提高页面的灵活性和用户体验。
|
10天前
|
JSON 移动开发 数据格式
html5+css3+js移动端带歌词音乐播放器代码
音乐播放器特效是一款html5+css3+js制作的手机移动端音乐播放器代码,带歌词显示。包括支持单曲循环,歌词显示,歌曲搜索,音量控制,列表循环等功能。利用json获取音乐歌单和歌词,基于html5 audio属性手机音乐播放器代码。
54 6
|
19天前
|
存储 JavaScript 前端开发
js事件队列
【10月更文挑战第15天】
40 6
|
21天前
|
JavaScript API
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
56 0
|
29天前
|
JavaScript
js两种移除事件的方法
js两种移除事件的方法
51 0
|
1月前
|
前端开发 JavaScript
JavaScript动态渲染页面爬取——CSS位置偏移反爬案例分析与爬取实战
JavaScript动态渲染页面爬取——CSS位置偏移反爬案例分析与爬取实战