使用CSS3实现开红包特效

这是我参与更文挑战的第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
喜欢就支持一下吧
点赞0 分享