这是我参与更文挑战的第4天,活动详情查看:更文挑战
小程序上发红包给用户有两种形式,一种是采用订阅消息的形式给用户发信息,用户点开就可以领红包,一种是自己实现领红包的效果,领完后自动将领取到的金额打到用户的微信账上,由于业务需要我们采用的是第二种方式。
效果预览
录屏的效果不是很好,实际上并没有那么卡,从底部射出是很流畅的;
入场动画
需要达到的效果:
- 从底部射出 – 缓入缓出
- 射出时红包大小从0到1
- 射出时透明度从0到1
难点:射出时怎么放到指定的位置,让红包有序排列,适配不同机型?
我的做法是,红包本来就居中排列好了,但我将红包移到屏幕居中且不可视区域的位置,在我点击打开红包时将红包的translate
的x轴以及y轴都设为0,就能达到上图的射出效果;
<view
:style="[initPosition( index )]"
v-for="( item, index ) in 5" :key="index"
>
<span>红包主体<span>
</view>
computed:{
initPosition() {
return index => {
let style = {};
let _action = {
'packet_0': _ => {
style.transform = `translate(${ this.handleDistance( index ) }) scale(0)`;
style.opacity = 0;
},
'packet_1': _ => {
style.transform = `translate(${ this.handleDistance( index ) }) scale(0)`;
style.opacity = 0;
},
'packet_2': _ => {
style.transform = `translate(${ this.handleDistance( index ) }) scale(0)`;
style.opacity = 0;
},
'packet_3': _ => {
style.transform = `translate(${ this.handleDistance( index ) }) scale(0)`;
style.opacity = 0;
},
'packet_4': _ => {
style.transform = `translate(${ this.handleDistance( index ) }) scale(0)`;
style.opacity = 0;
},
'default': _ => ''
};
const branch = _action[`packet_${index}`] || _action['default'];
branch.call(this);
return style;
}
},
}
handleDistance( index ) {
const _action = {
'hobbies_1_0': _ => '0rpx,1400rpx',
'hobbies_2_0': _ => '180rpx,1450rpx',
'hobbies_2_1': _ => '-165rpx,1450rpx',
'hobbies_3_0': _ => '0, 1250rpx',
'hobbies_3_1': _ => '50%, 800rpx',
'hobbies_3_2': _ => '-157rpx, 800rpx',
'hobbies_4_0': _ => '180rpx, 1450rpx',
'hobbies_4_1': _ => '-165rpx, 1450rpx',
'hobbies_4_2': _ => '180rpx, 800rpx',
'hobbies_4_3': _ => '-175rpx, 800rpx',
'hobbies_5_0': _ => '235rpx, 1450rpx',
'hobbies_5_1': _ => '0rpx, 1450rpx',
'hobbies_5_2': _ => '-230rpx, 1450rpx',
'hobbies_5_3': _ => '165rpx, 950rpx',
'hobbies_5_4': _ => '-165rpx, 950rpx'
}
const branch = _action[`hobbies_${this.prize.length}_${index}`] || _action['default'];
const res = branch.call(this);
return res;
},
复制代码
- 上述代码可以看到设置默认样式
scale(0)
对应的是大小从0到1,opacity = 0
对应的是透明度从0到1; handleDistance
函数的hobbies_x_x
从1到4大家都不用看了,实际业务上不同红包对应的是不同形态,但我们这里只看有5个红包的情况,也就是从hobbies_5_0
开始看,假设触发的是5_0组合,返回接收的结果就是translate(235rpx,1450rpx) scale(0)
;
打开红包射出
点击打开红包时,迅速设置translate(0,0)
即可快速归位;
handlePosition() {
return index => {
let style = '';
let _action = {
'packet_0': _ => {
style = 'r-show-repacket-0'
},
'packet_1': _ => {
style = 'r-show-repacket-1';
},
'packet_2': _ => {
style = 'r-show-repacket-2';
},
'packet_3': _ => {
style = 'r-show-repacket-3';
},
'packet_4': _ => {
style = 'r-show-repacket-4';
},
'default': _ => ''
};
const branch = _action[`packet_${index}`] || _action['default'];
this.show && branch.call(this);
return style;
}
},
// 示例
.r-show-repacket-0 {
transform: translate( 0, 0 ) scale(1) !important;
opacity: 1 !important;
}
复制代码
从底部射出时不是五个一起射出的,而是有间隔的射出,因此从第二个包开始就设置延迟即可transition-delay: .15s;
,这样就能达到依次射出回归到原来的位置;
翻转开红包动画
需要达到的效果
- 按钮有一个按住的效果
- 整个红包被金光包围,并进行翻转,当前点击的红包翻转成功后金光往右上角闪出,剩下的红包自动翻转,并且被点击的红包闪过第二道光;
按住的效果
.PressDown {
transition: all .6s;
animation: btndown .4s both ease-in-out;
}
@keyframes btndown {
0% {
transform: scale(0.9);
opacity: .6;
}
60% {
transform: scale(1);
opacity: 1;
}
100% {
opacity: 0;
}
}
复制代码
利用帧动画让用户产生按下去的效果,实际上是缩放按钮的大小配合过渡形成了按下去的感觉;
红包翻转
红包的翻转实际上是利用了preserve-3d
设置3D效果,此属性想要生效必须配合perspective
属性进行设置,这个值决定了3D效果的强烈程度 越小感觉越强烈;
rollback {
transition: transform 2s;
transform-style: preserve-3d;
animation: PacketRollback .5s .5s both linear;
}
@keyframes PacketRollback {
60% {
transform: rotateY(140deg) scale(1.2);
}
80% {
transform: rotateY(160deg) scale(1.1);
}
to {
transform: rotateY(180deg) scale(1);
}
}
复制代码
金光闪出都是控制translate
进行移出红包的可视范围,从按下开红包到翻转结束,我们需要注意的是每个动画该执行的时机,使用延时进行设置,每个时机执行对应的动画,就能一气呵成;
烟花炸开动画
在上面的效果预览中烟花是一张图片,只是将图片进行缩放以及透明度进行变化;
.Onefry {
animation: leftScalePack .5s .4s both cubic-bezier(.2,.01,.4,1);
}
@keyframes leftScalePack {
20% {
opacity: 1;
}
to {
transform: scale(4);
opacity: 0;
}
}
复制代码
总结
本文介绍了自行实现开红包的效果思路,感兴趣的小伙伴可以了解一下。写得不好的地方,请多多包涵。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END