Files
rating/components/SuccessPopup/SuccessPopup.vue
2026-06-10 00:03:29 +08:00

187 lines
4.5 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="success-popup" v-if="visible" @touchmove.stop.prevent>
<view class="mask" :class="{ 'mask-show': showAnim }" @tap="close"></view>
<view class="popup-content" :class="{ 'content-show': showAnim }">
<view class="icon-wrap">
<text class="emoji">{{ actionData?.emoji || '✨' }}</text>
<!-- 环形扩散特效 -->
<view class="ring ring-1"></view>
<view class="ring ring-2"></view>
<!-- 星星点缀 -->
<view class="sparkle s-1"></view>
<view class="sparkle s-2"></view>
<view class="sparkle s-3"></view>
</view>
<text class="title">{{ type === 'comment' ? '评论成功' : type === 'release' ? '已提交审核' : '评分成功' }}</text>
<text class="subtitle" v-if="type === 'comment'">{{ actionData?.label || '你的锐评已发布' }}</text>
<text class="subtitle" v-else-if="type === 'release'">{{ actionData?.label || '请耐心等待管理员审核' }}</text>
<text class="subtitle" v-else>你已将TA评价为{{ actionData?.label || '...' }}</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const visible = ref(false);
const showAnim = ref(false);
const actionData = ref(null);
const type = ref('rating');
let timer = null;
const show = (action, popupType = 'rating') => {
actionData.value = action;
type.value = popupType;
visible.value = true;
// 留一点时间让DOM渲染然后添加动画类
setTimeout(() => {
showAnim.value = true;
}, 50);
if (timer) clearTimeout(timer);
// 2秒后自动关闭
timer = setTimeout(() => {
close();
}, 2000);
};
const close = () => {
showAnim.value = false;
setTimeout(() => {
visible.value = false;
}, 300); // 等待淡出动画结束
};
defineExpose({
show,
close
});
</script>
<style lang="scss" scoped>
.success-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
}
.mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(4px);
opacity: 0;
transition: opacity 0.3s ease;
}
.mask.mask-show {
opacity: 1;
}
.popup-content {
position: relative;
width: 460rpx;
background-color: #ffffff;
border-radius: 40rpx;
padding: 64rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
opacity: 0;
transform: scale(0.8) translateY(20rpx);
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.15);
}
.popup-content.content-show {
opacity: 1;
transform: scale(1) translateY(0);
}
.icon-wrap {
position: relative;
width: 160rpx;
height: 160rpx;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 40rpx;
}
.emoji {
font-size: 100rpx;
position: relative;
z-index: 10;
animation: emojiBounce 1.2s infinite alternate ease-in-out;
}
@keyframes emojiBounce {
0% { transform: translateY(0) scale(1); }
100% { transform: translateY(-12rpx) scale(1.05); }
}
.ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
border: 4rpx solid #4d44f1;
opacity: 0;
}
.ring-1 {
animation: ripple 1.6s cubic-bezier(0.21, 0.53, 0.56, 0.8) infinite;
}
.ring-2 {
animation: ripple 1.6s cubic-bezier(0.21, 0.53, 0.56, 0.8) infinite 0.8s;
}
@keyframes ripple {
0% { width: 100rpx; height: 100rpx; opacity: 0.8; }
100% { width: 260rpx; height: 260rpx; opacity: 0; }
}
.sparkle {
position: absolute;
font-size: 32rpx;
opacity: 0;
z-index: 11;
}
.s-1 { top: -10rpx; right: -20rpx; animation: popStar 1.4s ease-out infinite 0.1s; }
.s-2 { bottom: 10rpx; left: -30rpx; animation: popStar 1.4s ease-out infinite 0.6s; font-size: 24rpx; }
.s-3 { top: 60rpx; left: -40rpx; animation: popStar 1.4s ease-out infinite 1.1s; font-size: 28rpx; }
@keyframes popStar {
0% { transform: scale(0) rotate(0deg); opacity: 0; }
30% { transform: scale(1.2) rotate(45deg); opacity: 1; }
80% { transform: scale(0) rotate(90deg); opacity: 0; }
100% { transform: scale(0) rotate(90deg); opacity: 0; }
}
.title {
font-size: 40rpx;
font-weight: 800;
color: #111;
margin-bottom: 16rpx;
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
}
.subtitle {
font-size: 28rpx;
color: #666;
text-align: center;
}
</style>