更新
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<view class="vsm" :class="[`vsm--${size}`, { 'vsm--active': active, 'vsm--on-dark': onDark }]">
|
||||
<view class="vsm-body">
|
||||
<view class="vsm-leaf" aria-hidden="true" />
|
||||
<view class="vsm-face">
|
||||
<view class="vsm-eye vsm-eye--l" />
|
||||
<view class="vsm-eye vsm-eye--r" />
|
||||
<view class="vsm-blush vsm-blush--l" />
|
||||
<view class="vsm-blush vsm-blush--r" />
|
||||
<view class="vsm-mouth" />
|
||||
</view>
|
||||
<view v-if="active" class="vsm-waves" aria-hidden="true">
|
||||
<view class="vsm-wave vsm-wave--1" />
|
||||
<view class="vsm-wave vsm-wave--2" />
|
||||
<view class="vsm-wave vsm-wave--3" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
/** 正在按住说话 / 录音中 */
|
||||
active: { type: Boolean, default: false },
|
||||
/** 深色条背景上使用浅色卡通 */
|
||||
onDark: { type: Boolean, default: false },
|
||||
size: { type: String, default: 'md' }
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.vsm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.vsm--md { width: 72rpx; height: 72rpx; }
|
||||
.vsm--sm { width: 64rpx; height: 64rpx; }
|
||||
|
||||
.vsm-body {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vsm-leaf {
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
left: 50%;
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
margin-left: -8rpx;
|
||||
border-radius: 0 100% 0 100%;
|
||||
background: #34d399;
|
||||
transform: rotate(-18deg);
|
||||
z-index: 2;
|
||||
}
|
||||
.vsm--on-dark .vsm-leaf {
|
||||
background: #a7f3d0;
|
||||
}
|
||||
|
||||
.vsm-face {
|
||||
position: relative;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 50%;
|
||||
background: #fef9c3;
|
||||
border: 3rpx solid #047857;
|
||||
box-shadow: 0 4rpx 10rpx rgba(4, 120, 87, 0.18);
|
||||
z-index: 1;
|
||||
}
|
||||
.vsm--sm .vsm-face {
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
}
|
||||
.vsm--on-dark .vsm-face {
|
||||
background: #fffbeb;
|
||||
border-color: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.vsm-eye {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
width: 6rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 50%;
|
||||
background: #064e3b;
|
||||
}
|
||||
.vsm--sm .vsm-eye { top: 14rpx; width: 5rpx; height: 7rpx; }
|
||||
.vsm--on-dark .vsm-eye { background: #134e4a; }
|
||||
.vsm-eye--l { left: 12rpx; }
|
||||
.vsm-eye--r { right: 12rpx; }
|
||||
.vsm--sm .vsm-eye--l { left: 10rpx; }
|
||||
.vsm--sm .vsm-eye--r { right: 10rpx; }
|
||||
|
||||
.vsm-blush {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
width: 10rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(251, 113, 133, 0.45);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.vsm--sm .vsm-blush { top: 21rpx; width: 8rpx; height: 5rpx; }
|
||||
.vsm-blush--l { left: 6rpx; }
|
||||
.vsm-blush--r { right: 6rpx; }
|
||||
.vsm--on-dark .vsm-blush { background: rgba(255, 255, 255, 0.35); }
|
||||
|
||||
.vsm-mouth {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 10rpx;
|
||||
width: 18rpx;
|
||||
height: 8rpx;
|
||||
margin-left: -9rpx;
|
||||
border-radius: 0 0 18rpx 18rpx;
|
||||
background: #047857;
|
||||
transform-origin: center top;
|
||||
}
|
||||
.vsm--sm .vsm-mouth {
|
||||
bottom: 9rpx;
|
||||
width: 16rpx;
|
||||
height: 7rpx;
|
||||
margin-left: -8rpx;
|
||||
}
|
||||
.vsm--on-dark .vsm-mouth { background: #ecfdf5; }
|
||||
|
||||
.vsm-waves {
|
||||
position: absolute;
|
||||
right: -2rpx;
|
||||
top: 50%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 4rpx;
|
||||
height: 28rpx;
|
||||
margin-top: -14rpx;
|
||||
z-index: 0;
|
||||
}
|
||||
.vsm-wave {
|
||||
width: 5rpx;
|
||||
border-radius: 4rpx;
|
||||
background: #047857;
|
||||
animation: vsm-wave-jump 0.72s ease-in-out infinite;
|
||||
}
|
||||
.vsm--on-dark .vsm-wave { background: rgba(255, 255, 255, 0.9); }
|
||||
.vsm-wave--1 { height: 10rpx; animation-delay: 0s; }
|
||||
.vsm-wave--2 { height: 18rpx; animation-delay: 0.12s; }
|
||||
.vsm-wave--3 { height: 12rpx; animation-delay: 0.24s; }
|
||||
|
||||
.vsm--active .vsm-body {
|
||||
animation: vsm-bob 0.9s ease-in-out infinite;
|
||||
}
|
||||
.vsm--active .vsm-mouth {
|
||||
animation: vsm-talk 0.32s ease-in-out infinite alternate;
|
||||
}
|
||||
.vsm--active .vsm-eye {
|
||||
animation: vsm-blink 2.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes vsm-bob {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-4rpx); }
|
||||
}
|
||||
@keyframes vsm-talk {
|
||||
0% {
|
||||
transform: scaleY(0.45);
|
||||
border-radius: 0 0 18rpx 18rpx;
|
||||
}
|
||||
100% {
|
||||
transform: scaleY(1.15);
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
@keyframes vsm-blink {
|
||||
0%, 42%, 46%, 100% { transform: scaleY(1); }
|
||||
44% { transform: scaleY(0.15); }
|
||||
}
|
||||
@keyframes vsm-wave-jump {
|
||||
0%, 100% { transform: scaleY(0.45); opacity: 0.55; }
|
||||
50% { transform: scaleY(1); opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user