作为一个有抠细节前端人,对自己写的页面代码总是要搞点什么事情,看到之前写的点赞按钮太单一没点的欲望,索性给其加一个小动画,增强用户的体验也治好了自己的强迫症。废话不多说,无图无真相。
当然你看到的是一个简版,但是功能需求啥的都是有的,就比如说,点击小心心弹动数字加一减一,点击其他的按钮控制数字变化,再就是重要的数字的滚动变化,在9,99,999加减的时候的滚动处理。
❤️爱心效果
这个不用细说,很简单的使用了 transform
的 scale
,用到动画就是贝塞尔曲线率 cubic-bezier(.22, .93, .53, 1.25)
,为什么是这些呢?因为我需要在点击的时候加一个放大到最大超出然后缩小到本身的大小的效果,如下图:
这样的话动画就满足我想要的效果。
其中这里面点赞和未点赞是两个不一样的图标,我把这两个都是定位设置,默认都是一个 opacity
的状态,只有点击的时候才会显示需要展示的图标,再给其加上相应的动画效果。
具体代码 css
部分:
.y-like .heart {
width: 18px;
height: 12px;
position: relative;
}
// 添加点击的扩展区
.y-like .heart::after {
content: '';
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
}
.y-like .heart .fa {
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 14px;
transform: scale(0);
transition: all .3s cubic-bezier(.22, .93, .53, 1.25);
}
.y-like .heart .fa.active {
opacity: 1;
transform: scale(1);
}
.y-like .heart .fa.fa-heart.active {
color: red;
}
dom
部分:
<div class="heart">
<i class="fa fa-heart-o active"></i>
<i class="fa fa-heart"></i>
</div>
数字滚动动画
我当时做的时候是用 0 - 9
一列的数字变化做的效果,通过文字的上下滚动给其加上 transform
定位到显示的数字上,外层的 dom
会做一个 overflow
的处理,不让其他的数字都展示出来,但是弄出来之后发现效果并不是最佳的,从视觉感受来看滚动的时候上面总是有个东西遮住了滚动,总感觉是非常的别扭的,所以我去掉了外层的 overflow
的影响,使用的是定位的方式,动画方面采用的是 keyframes
模式给数字加向上或者向下的渐隐效果。
先看数字滚动部分的 dom
布局
<div class="count">
<div class="num">
<span class="upupin"></span>
<span class="upup"></span>
</div>
<div class="num">
<span class="upupin"></span>
<span class="upup"></span>
</div>
</div>
解释一下,为啥这样写,一个数字过来我们不知道是多少位数,可能是单数或者说是双数又或者是3三位数,这是通过数字的拆分,放到里面处理的,在每个数字里面,我又做了它的下级数字或者上级数字,到滚动的时候就可以做数字的偏移即可,当滚动开始时就先去计算好了数字是向上或者向下滚动,通过数字的大小来类比方向,然后给数字加上特定的 class
再 innerHTML
中就可以了。废话文字说了这么多,还是得看图:
这是一个向上推的一个过程,为什么会这样,其实是写的 animation
的作用,向上的时候我加的样式是upupin
upup
,对应的 keyframes
是一个从 0 -> -100% 的一个过程和 100% ->0 的一个过程。同理反过来是一样的操作,向下的时候加的样式是 downin
down
。因为在设置数字的外层 dom 时高度宽度固定,所以数字的 dom 定位高度就直接可以写成 100% 或者 -100%,这样就可以完美的滚动加渐隐效果了。
具体看代码:
@keyframes down {
0% {
opacity: 0;
transform: translateY(-100%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes downin {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(100%);
}
}
@keyframes upup {
0% {
opacity: 0;
transform: translateY(100%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes upupin {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-100%);
}
}
差不多问题的核心就说完了,本质上就是借助了css 的动画偏移来做到上下滚动,接下去剩下的点就是怎么处理数字的大小的问题了。
要做到文字的对比,首先应该想到的是把数字全都拆离出来,传入的数字都进行 toString()
处理,反向循环每一个数字的并一次性加入到 DOM
中,比较二次传入的数字和第一次传的数字给不同方向的数字加入不一样的 class
,其中循环的次数就是获取的 .num
的 dom
元素个数, 但是整理有几个处理的临界点,首先就是当数字小于本身的长度时,或者大于本身的长度时,这时候就需要多添加一个空的数字进去,以保证正常的渲染。当然也要记得结束之后,把新的数字保存以便下次更新对比。看代码:
var len = 0
if (oldNum.length < newNum.length) {
oldNum.push('')
len = oldNum.length - 1
this.element.querySelector('.count').insertAdjacentHTML('beforeEnd', '<div class="num"><span></span></div>')
} else if (oldNum.length > newNum.length) {
newNum.push('')
len = newNum.length - 1
setTimeout(function () {
nums[nums.length - 1].remove()
}, 300)
} else {
len = oldNum.length - 1
}
for (var i = len; i >= 0; i--) {
if (oldNum[i] !== newNum[i]) {
// 通过前后的数字判断是否是向上滚动还是向下滚动
if (oldValue < newValue) {
h = '<span class="upupin">' + oldNum[i] + '</span>' +
'<span class="upup">' + newNum[i] + '</span>'
} else {
h = '<span class="down">' + newNum[i] + '</span>' +
'<span class="downin">' + oldNum[i] + '</span>'
}
this.element.querySelectorAll('.count .num')[i].innerHTML = h
}
}
// 结束之后重新保存新数字
this.value = newValueStr
处理完了上面的之后就差不多算完成了,再加上几个内置 api
处理加一减一和自动点击处理返回点击之后的数字就好了。
下面看一下 预览效果