1.实现效果
![](https://img.haomeiwen.com/i26325037/7366736889d953e9.gif)
2.实现原理
wx.createAnimation(Object object):创建一个动画实例 animation。调用实例的方法来描述动画。最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。
- 点击红包,弹出红包弹框,用到过渡动画
this.animation.translate('-50%', '-50%').step();
- 关闭弹框
this.animation.translate('-50%', '100%').step();
- 将红包弹框拆分成两部分,后续点击开红包时候的上下两部分反向淡出动画
animation1.translateY('-350%').step();
animation2.translateY('300%').step()
- 当开红包动画结束,关闭弹框,并清除动画,这里用opacity来清除动画(一般情况按照原来的样式复原即可,因为该处原本无transfrom属性,还原动画若添加transfrom会影响页面布局,即用opacity)
animation1.opacity(1).step();
animation2.opacity(1).step();
- 上下两部分的圆弧用伪元素+border-radius+box-shadow实现
- 点击开红包,添加动画
@keyframes rotate {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
3.实现代码
<view class="flex">
<image src="https://i.postimg.cc/mgsKJGLw/susu1.jpg" class="user_avatar" />
<view class="wallet_box" catchtap="show">
<view class="flex-row j_c">
<image src="../img/red.png" class="red_icon" />
<view>恭喜发财,大吉大利</view>
</view>
<view class="wallet_tip">微信红包</view>
</view>
</view>
<!-- 红包弹框 -->
<view class="mask" hidden="{{!show}}"></view>
<view class="red_box flex-column" animation="{{animationData}}" hidden="{{!show}}">
<view class="top flex-column" animation="{{animationData1}}">
<view class="flex-row">
<image src="https://i.postimg.cc/mgsKJGLw/susu1.jpg" class="user_avatar_dia" />
<view>小苏苏的红包</view>
</view>
<view class="text">恭喜发财,大吉大利</view>
<view class="top_radius">
<view class="open" catchtap="open" wx:if="{{not_open}}">開</view>
<view wx:else class="anim-rotate">
<view class="roate_box" style="transform: translateZ(-3px);">開</view>
<view class="roate_box roate_box_center" wx:for="{{5}}" wx:key="index" style="transform:translateZ({{index-3}}px)"></view>
<view class="roate_box roate_box_center" style="transform: translateZ(3px);">開</view>
</view>
</view>
</view>
<view class="bottom" animation="{{animationData2}}">
<view class="line"></view>
<view class="bottom_box"></view>
</view>
<image src="/img/close_icon.png" class="close_icon" catchtap="closeModal" />
</view>
/* pages/effects/clipRed/index.wxss */
page {
padding: 20rpx;
box-sizing: border-box;
background-color: #fff;
}
.user_avatar {
width: 60rpx;
height: 60rpx;
border-radius: 10rpx;
flex-shrink: 0;
margin-right: 30rpx;
}
.wallet_box {
position: relative;
width: 360rpx;
height: 140rpx;
border-radius: 10rpx;
background-color: orange;
box-sizing: border-box;
padding: 10rpx 21rpx;
color: #fff;
font-size: 25rpx;
}
.red_icon {
width: 70rpx;
height: 70rpx;
flex-shrink: 0;
margin-right: 10rpx;
}
.wallet_box::after {
content: '';
position: absolute;
top: 20rpx;
left: -15rpx;
width: 0;
height: 0;
border-top: 20rpx solid transparent;
border-bottom: 20rpx solid transparent;
border-right: 20rpx solid orange;
}
.wallet_tip {
border-top: 1rpx solid rgb(255, 255, 255, .2);
margin-top: 10rpx;
padding-top: 10rpx;
font-size: 20rpx;
}
.red_box {
position: fixed;
left: 50%;
transform: translate(-50%, 100%);
top: 50%;
color: rgb(235, 205, 153);
width: 530rpx;
z-index: 1222;
font-size: 27rpx;
}
.top {
position: relative;
border-radius: 15rpx 15rpx 0 0;
width: 100%;
padding: 175rpx 0 0rpx;
box-sizing: border-box;
background-color: #f45e4d;
}
.top_radius {
width: 100%;
height: 100px;
position: relative;
}
.top_radius::after {
width: 100%;
height: 100px;
position: absolute;
left: 0;
top: 52px;
content: '';
border-radius: 50%;
z-index: 10;
background-color: rgb(244, 94, 77);
box-shadow: 0 3px 3px 0 rgb(0 0 0 / 10%);
}
.close_icon {
position: absolute;
width: 50rpx;
height: 50rpx;
bottom: -91rpx;
}
.user_avatar_dia {
margin-right: 10rpx;
width: 40rpx;
height: 40rpx;
border-radius: 8rpx;
flex-shrink: 0;
}
.text {
font-size: 36rpx;
margin-top: 20rpx;
}
.bottom {
overflow: hidden;
width: 100%;
margin-top: -70rpx;
}
.bottom_box {
margin-top: 70rpx;
height: 240rpx;
background-color: rgb(242 85 66);
border-radius: 0 0 15rpx 15rpx;
}
.line {
width: 100%;
position: relative;
}
.line::after {
width: 120%;
height: 140rpx;
position: absolute;
left: -10%;
top: -70rpx;
z-index: -1;
content: '';
border-radius: 50%;
box-shadow: 0 30px 0 0 rgb(242 85 66);
}
.open {
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
position: absolute;
left: 50%;
z-index: 99;
bottom: -161rpx;
border-radius: 50%;
width: 130rpx;
height: 130rpx;
line-height: 130rpx;
font-size: 45rpx;
text-align: center;
color: #333;
font-weight: bold;
background-color: rgb(235, 205, 153);
box-shadow: 0 0 3rpx 0 rgb(0 0 0 / 10%);
}
.roate_box {
border-radius: 50%;
width: 130rpx;
height: 130rpx;
line-height: 130rpx;
font-size: 45rpx;
text-align: center;
color: #333;
font-weight: bold;
background-color: rgb(235, 205, 153);
box-shadow: 0 0 3rpx 0 rgb(0 0 0 / 10%);
}
.anim-rotate {
margin-left: -75rpx;
transform-style: preserve-3d;
animation: rotate 1s linear infinite;
position: absolute;
left: 50%;
z-index:90;
bottom: -161rpx;
}
@keyframes rotate {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
.roate_box_center {
position: absolute;
top: 0;
z-index: 99;
}
Page({
data: {
show: false,
not_open: true,
animationData: {},
animationData1: {},
animationData2: {},
},
closeModal() {
this.slideIn(1);
setTimeout(() => {
this.setData({
show: false
})
}, 200);
},
show() {
wx.showLoading({
title: '加载中...',
mask: true
})
setTimeout(() => {
this.setData({
show: true
}, (() => {
this.slideIn(0)
}))
wx.hideLoading();
}, 500);
},
open() {
this.setData({
not_open: false
}, (() => {
setTimeout(() => {
this.setData({
not_open: true,
})
this.fadeOut(() => {
let animation = wx.createAnimation({
duration: 0,
timingFunction: 'step-end'
})
let animation1 = wx.createAnimation({
duration: 0,
timingFunction: 'step-end'
})
animation.opacity(1).step();
animation1.opacity(1).step();
this.setData({
show: false,
animationData1: animation.export(),
animationData2: animation1.export(),
})
})
}, 1000);
}))
},
....
})
网友评论