借助CSS来管理js事件

栏目: CSS · 发布时间: 6年前

内容简介: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>

借助CSS来管理js事件

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

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来控制

这里封装了一下自定义事件,可以更好的在项目中使用(虽然代码本身就很少了)。

借助CSS来管理js事件

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

借助CSS来管理js事件

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

借助CSS来管理js事件

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

借助CSS来管理js事件

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

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

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

借助CSS来管理js事件

所以我们来看第二种方式

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

查看这个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都很棘手的问题,可能还会有更多的应用场景,欢迎小伙伴留言讨论~


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro CSS Techniques

Pro CSS Techniques

Jeff Croft、Ian Lloyd、Dan Rubin / Apress / 2009-5-4 / GBP 31.49

Web Standards Creativity: Innovations in Web Design with CSS, DOM Scripting, and XHTML一起来看看 《Pro CSS Techniques》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换