这里记录工作中遇到的技术点,以及自己对生活的一些思考,周三或周五发布。
封面图
在复兴号列车
转盘抽奖前端实现方案
需求
前几天有个朋友让我帮他写一个转盘抽奖的效果,大体的要求有这么两个:
- 未点击抽奖按钮时,转盘外围有一圈交替明暗的灯珠
- 抽奖过程中转盘外围的灯珠变成跑马灯的效果
- 奖品的数量可以配置为6或8个
- 按钮点击要有一个按下后弹起的动作
示意图:
分析
用图片实现
要实现这个几个功能,最简单的方式是使用图片。比方说,明暗交替的灯珠采用gif来实现,这种使用图片的方式实现起来比较方便,但是在网络情况不好的条件下,图片的切换过程中,图片加载需要一定的时间,转盘的盘面会出现一段时间的空白,整体的体验就会差了一些。
用css实现
毫无疑问,按钮点击有一个弹起的动作以及明暗交替的灯珠是可以用css来进行实现的。
按钮点击弹起
按钮点击弹起,这个效果可以用:active
这个伪类进行实现。很多人都知道:active
这个伪类可以用在<a>
标签上,但是其实它也可以用在button
按钮上。具体可以查看它的使用方式
:active
伪类一般被用在 <a>
和 <button>
元素中。这个伪类的一些其他适用对象包括包含激活元素的元素,以及可以通过他们关联的<label>
标签被激活的表格元素。
所以这个按钮点击的效果实现起来就比较简单:
button::active{
tarnsform:scale(0.98);
}
复制代码
大致就这么简单。
灯珠明暗交替
灯珠的效果需要我们先把灯珠按照相应的布局画到页面上。绘制的过程通常是根据转盘的容器进行定位,然后旋转相应的角度。
比如这里有8个奖品,24颗灯珠,单个旋转的角度就是360/24=15
度。然后根据每个(灯珠的下标+1)*15
就是每个灯珠具体需要旋转的角度。
灯珠的位置固定好以后,就可着手实现明暗交替的效果,这个效果可以用css的animation
来实现,具体方案是的解释如下:
- 先根据灯珠的奇偶,分别着不同的颜色
- 设置动画,根据灯珠的奇偶(下标)设置动画
<View className={styles.lightItemActive}
style={{
width: '117px',
transform: `translateX(-50%) rotate(${(360 / (activeDetail.prize.length * 3)) * item}deg)`
'--color-white':(item+1)%2?'#fff':'#93b3ff',
'--color-blue':(item+1)%2?'#93b3ff':'#fff',
'--char-index':item
}}
>
<View
className={styles.bubble}
style={{
background: item % 2 == 0 ? colorCircleFirst : colorCircleSecond,
boxShadow:
item % 2 == 0
? `0 0 5rpx ${filterOne},
0 0 10rpx ${filterOne},
0 0 20rpx ${filterOne},
0 0 40rpx ${filterOne},
0 0 80rpx ${filterOne}`
: `0 0 5rpx ${filterTwo},
0 0 10rpx ${filterTwo},
0 0 20rpx ${filterTwo},
0 0 40rpx ${filterTwo},
0 0 80rpx ${filterTwo}`
// filter:((item)%2==0)?'drop-shadow(0px 0px 10px'+ filterOne+') brightness(3)':'drop-shadow(0px 0px 10px '+filterTwo+') brightness(3)',
}}
></View>
</View>
复制代码
我这dom 没有参考性,只是举个例子。
然后设置动画
.bubble{
animation:flash 1s linear infinite;
}
@keyframes flash {
0% {background: var(--color-white);}
25% {background: var(--color-blue);}
50% {background: var(--color-white);}
100% {background: var(--color-blue);}
复制代码
灯珠的跑马灯效果
跑马灯用css实现可以参考下面的效果:
其方案也可以理解为是用下标,设置不同的元素的颜色,然后通过延时动画,设置元素的背景,以及drop-shadow
来实现,其关键代码如下:
.showcase__text .char {
-webkit-animation-delay: calc(((var(--char-index) + 1) * var(--step)) * 1s);
animation-delay: calc(((var(--char-index) + 1) * var(--step)) * 1s);
-webkit-animation-duration: calc(var(--duration) * 1s);
animation-duration: calc(var(--duration) * 1s);
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-name: flash;
animation-name: flash;
background: #000;
text-shadow: 0 4px 0 #000;
}
@keyframes flash {
0%, 30%, 50%, 100% {
background: #000;
}
40% {
background: var(--color);
-webkit-filter: drop-shadow(0 0 calc(var(--font-size) * 1rem) var(--color)) blur(2px) brightness(5);
filter: drop-shadow(0 0 calc(var(--font-size) * 1rem) var(--color)) blur(2px) brightness(5);
}
}
复制代码
注意:它使用了-animation-delay
属性,如果不设置这个属性,则没有跑马灯的效果。
需要考虑的问题
- 小程序端
因为我这次写的这个效果的场景运行在小程序上。前期整体的效果采用css来实现,由于animation的间歇调用,加上时间动画时间比较短,所以整体上会有一个非常明显的闪顿
的效果,不是卡顿。比如我设置的动画时长是1s,则每一秒动画完成后,整体会有个非常明显的闪的效果,这种体验非常不好。
采用js方案实现
基于上面说的原因。整体的方案又重新改成了js来实现,js实现起来非常简单。
灯珠交替明暗
灯珠交替明暗这个效果用定时器设置两种不同的颜色,当灯珠颜色为a时设置为b,为b时设置为a即可。
<View
className={styles.bubble}
style={{
background: item % 2 == 0 ? colorCircleFirst : colorCircleSecond,
boxShadow:
item % 2 == 0
? `0 0 5rpx ${filterOne},
0 0 10rpx ${filterOne},
0 0 20rpx ${filterOne},
0 0 40rpx ${filterOne},
0 0 80rpx ${filterOne}`
: `0 0 5rpx ${filterTwo},
0 0 10rpx ${filterTwo},
0 0 20rpx ${filterTwo},
0 0 40rpx ${filterTwo},
0 0 80rpx ${filterTwo}`
// filter:((item)%2==0)?'drop-shadow(0px 0px 10px'+ filterOne+') brightness(3)':'drop-shadow(0px 0px 10px '+filterTwo+') brightness(3)',
}}
></View>
复制代码
//灯珠交替
setTimeout(function () {
if (colorCircleFirst === 'linear-gradient(-17deg, #fff, #FFFFFF)') {
setColorCircleFirst('linear-gradient(-17deg, #9DD6FF, #EFF9FF)')
setColorCircleSecond('linear-gradient(-17deg, #fff, #FFFFFF)')
setFilterOne('#3091FF')
setFilterTwo('#fff')
}
if(colorCircleFirst === 'linear-gradient(-17deg, #9DD6FF, #EFF9FF)'){
setColorCircleFirst('linear-gradient(-17deg, #fff, #FFFFFF)')
setColorCircleSecond('linear-gradient(-17deg, #9DD6FF, #EFF9FF)')
setFilterOne('#fff')
setFilterTwo('#3091FF')
}
}, 500)
复制代码
跑马灯
跑马灯用js实现起来也很简单,给灯珠设置一个颜色,然后设置一个数字,当灯珠下标等于这个数字时,设置灯珠颜色即可。
我们需要做的就是通过定时器控制这个数字变化的速度,然后在转盘动画结束后清除定时器。
<View className={styles.bubble}
style={{
background:
(item + 1) % 2
? 'linear-gradient(-17deg, #fff, #fff)'
boxShadow:
selectLightIndex === item
? `0 0 10rpx #fff,
0 0 20rpx #fff,
0 0 40rpx #fff,
0 0 80rpx #fff,
0 0 100rpx #fff`
: ''
}}
></View>
复制代码
let i = 0;
var timer = setInterval( ()=> {
selectLightIndex++;
i += 40;
selectLightIndex = selectLightIndex%24
setSelectLightIndex(selectLightIndex)
//获奖提示
}, times*1 + i);
setTimeout(() => {
clearInterval(timer)
roateEnd(awardSettingNumber);
}, 5150);
复制代码
selectLightIndex%24
根据灯珠数量取余这个运算可以控制当前哪个灯珠亮起。
i += 40;
则可以控制转动的速度。
这样,转盘的整体效果就基本完成了。
点击抽奖按钮前,灯珠明暗交替。
点击抽奖按钮后,灯珠则是跑马灯效果。
其他问题
在写这个效果的是遇到一个多图片的marquee
效果。
使用css的transform:translate(x)
进行实现,当图片数量大于一定数量的时候,可以看到有非常明显的卡顿。
查了一些文档,说是需要使用translate3d()
开启硬件加速,但是不起作用,这个似乎暂时无解。
最后
以上就是写这个转盘抽奖效果的所有收获,希望能对有需要的同学有所帮助。
近期的事情有点多,暂时先写到这里吧~
如果喜欢。
请点赞和"在看"吧,最好也加个"关注",或者分享到朋友圈。
分享两张个人觉的不错的图片
暴雨之前的郑州(一)
暴雨之前的郑州(二)