feat(tabbar): tabBar改造

This commit is contained in:
woody 2025-07-25 16:00:11 +08:00
parent eb7a4f68eb
commit 93cad9032e
10 changed files with 710 additions and 24 deletions

View File

@ -0,0 +1,333 @@
<template>
<view class="raised-tabbar">
<!-- 背景遮罩层创建凸起效果 -->
<view class="tabbar-bg">
<view class="raised-circle"></view>
</view>
<!-- TabBar内容 -->
<view class="tabbar-content">
<!-- 左侧两个选项 -->
<view
v-for="(item, index) in leftItems"
:key="index"
class="tabbar-item"
:class="{ active: current === index }"
@click="tabbarChange(index)"
>
<view class="item-icon">
<image
:src="current === index ? item.activeIcon : item.inactiveIcon"
class="icon-normal"
/>
<view v-if="item.badge && item.badge > 0" class="badge">{{
item.badge
}}</view>
</view>
<text class="item-text" :class="{ active: current === index }">{{
item.text
}}</text>
</view>
<!-- 中间凸起的选项 -->
<view
class="tabbar-item center-item"
:class="{ active: current === 2 }"
@click="tabbarChange(2)"
>
<view class="center-icon-wrapper">
<view class="center-icon">
<image
:src="
current === 2 ? centerItem.activeIcon : centerItem.inactiveIcon
"
class="center-image"
/>
</view>
</view>
<text
class="item-text center-text"
:class="{ active: current === 2 }"
>{{ centerItem.text }}</text
>
</view>
<!-- 右侧两个选项 -->
<view
v-for="(item, index) in rightItems"
:key="index + 3"
class="tabbar-item"
:class="{ active: current === index + 3 }"
@click="tabbarChange(index + 3)"
>
<view class="item-icon">
<image
:src="current === index + 3 ? item.activeIcon : item.inactiveIcon"
class="icon-normal"
/>
<view v-if="item.badge && item.badge > 0" class="badge">{{
item.badge
}}</view>
</view>
<text class="item-text" :class="{ active: current === index + 3 }">{{
item.text
}}</text>
</view>
</view>
</view>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'RaisedTabbar',
props: {
current: {
type: Number,
default: 0,
},
},
data() {
return {
//
list: [
{
text: '首页',
path: 'pages/index/index',
},
{
text: '会员专区',
path: 'pages/specialArea/index',
},
{
text: '个人推广',
path: 'pages/mine/share/index',
},
{
text: '购物车',
path: 'pages/shoppingCar/index',
},
{
text: '我的',
path: 'pages/mine/index',
},
],
}
},
computed: {
...mapGetters(['shopCarLength']),
//
leftItems() {
return [
{
text: '首页',
activeIcon: require('@/static/images/one1.png'),
inactiveIcon: require('@/static/images/one2.png'),
},
{
text: '会员专区',
activeIcon: require('@/static/images/five1.jpg'),
inactiveIcon: require('@/static/images/five2.jpg'),
},
]
},
//
centerItem() {
return {
text: '个人推广',
activeIcon: require('@/static/images/code.svg'),
inactiveIcon: require('@/static/images/code.svg'),
}
},
//
rightItems() {
return [
{
text: '购物车',
activeIcon: require('@/static/images/three1.png'),
inactiveIcon: require('@/static/images/three2.png'),
badge: this.shopCarLength,
},
{
text: '我的',
activeIcon: require('@/static/images/fore1.png'),
inactiveIcon: require('@/static/images/fore2.png'),
},
]
},
},
methods: {
tabbarChange(index) {
this.$emit('change', index)
uni.switchTab({
url: '/' + this.list[index].path,
})
},
},
}
</script>
<style lang="scss" scoped>
.raised-tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
.tabbar-bg {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60px;
background: #ffffff;
//
// .raised-circle {
// position: absolute;
// top: -30rpx;
// left: 50%;
// transform: translateX(-50%);
// width: 110rpx;
// height: 110rpx;
// background: #ffffff;
// border-radius: 50%;
// box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
// }
//
&::after {
content: '';
position: absolute;
bottom: -40px;
left: 0;
right: 0;
height: env(safe-area-inset-bottom);
background: #ffffff;
}
}
.tabbar-content {
position: relative;
display: flex;
align-items: flex-end;
height: 60px;
padding-bottom: 5px;
background: transparent;
.tabbar-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-bottom: 5px;
position: relative;
.item-icon {
position: relative;
margin-bottom: 2px;
.icon-normal {
width: 20px;
height: 20px;
}
.badge {
position: absolute;
top: -5px;
right: -8px;
background: #ff4757;
color: white;
border-radius: 50%;
width: 16px;
height: 16px;
font-size: 10px;
text-align: center;
line-height: 16px;
display: flex;
align-items: center;
justify-content: center;
}
}
.item-text {
font-size: 10px;
color: #666666;
line-height: 1.2;
&.active {
color: #333333;
}
}
//
&.center-item {
position: relative;
.center-icon-wrapper {
position: absolute;
top: -60rpx;
background: #fff;
border-radius: 50%;
font-size: 0;
padding: 4rpx;
.center-icon {
width: 92rpx;
height: 92rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
// box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
position: relative;
//
animation: breathe 3s ease-in-out infinite;
.center-image {
width: 92rpx;
height: 92rpx;
// position: absolute;
// top: -10rpx;
}
//
// &.active {
// background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
// }
}
}
.center-text {
margin-top: 25px;
font-size: 9px;
}
&.active {
.center-icon-wrapper .center-icon {
// background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
transform: scale(1.1);
transition: all 0.3s ease;
}
}
}
}
}
}
//
@keyframes breathe {
0%,
100% {
transform: scale(1);
// box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
50% {
transform: scale(1.05);
// box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
}
}
</style>

View File

@ -271,7 +271,7 @@ export default {
.member-code-outer {
position: absolute;
bottom: 160rpx;
width: 500rpx;
width: 300rpx;
text-align: center;
background: rgb(217, 24, 25);
border-radius: 20rpx;

195
components/tabbar-test.vue Normal file
View File

@ -0,0 +1,195 @@
<template>
<view class="test-page">
<view class="test-content">
<view class="test-title">TabBar图标测试</view>
<!-- 显示当前状态 -->
<view class="status-info">
<text>当前选中: {{ currentTab }}</text>
<text>主题皮肤: {{ systemSkin }}</text>
<text>购物车数量: {{ shopCarLength || 0 }}</text>
</view>
<!-- 图标测试区域 -->
<view class="icon-test">
<view class="icon-section">
<text class="section-title">首页图标测试</text>
<view class="icon-row">
<image src="@/static/images/one1.png" class="test-icon" />
<image src="@/static/images/one2.png" class="test-icon" />
<image src="@/static/images/one11.jpg" class="test-icon" />
</view>
</view>
<view class="icon-section">
<text class="section-title">会员专区图标测试</text>
<view class="icon-row">
<image src="@/static/images/special1.png" class="test-icon" />
<image src="@/static/images/special2.png" class="test-icon" />
</view>
</view>
<view class="icon-section">
<text class="section-title">个人推广图标测试</text>
<view class="icon-row">
<image src="@/static/images/share-act.svg" class="test-icon" />
<image src="@/static/images/share.svg" class="test-icon" />
</view>
</view>
<view class="icon-section">
<text class="section-title">购物车图标测试</text>
<view class="icon-row">
<image src="@/static/images/three1.png" class="test-icon" />
<image src="@/static/images/three2.png" class="test-icon" />
<image src="@/static/images/three11.jpg" class="test-icon" />
</view>
</view>
<view class="icon-section">
<text class="section-title">我的图标测试</text>
<view class="icon-row">
<image src="@/static/images/my_icon1.png" class="test-icon" />
<image src="@/static/images/my_icon2.png" class="test-icon" />
</view>
</view>
</view>
<!-- 主题切换按钮 -->
<view class="theme-switcher">
<button @click="switchTheme" class="theme-btn">
切换主题 (当前: {{ systemSkin === 2 ? '绿色' : '默认' }})
</button>
</view>
</view>
<!-- 使用修复后的TabBar -->
<RaisedTabbar :current="currentTab" @change="handleTabChange" />
</view>
</template>
<script>
import RaisedTabbar from './raised-tabbar.vue'
import { mapGetters } from 'vuex'
export default {
name: 'TabbarTest',
components: {
RaisedTabbar,
},
data() {
return {
currentTab: 0,
}
},
computed: {
...mapGetters(['shopCarLength', 'user']),
systemSkin() {
return this.user?.skin || 0
},
},
methods: {
handleTabChange(index) {
this.currentTab = index
console.log('Tab切换到:', index)
},
switchTheme() {
// Vuex
if (this.user) {
this.$store.commit('updateUserSkin', this.systemSkin === 2 ? 0 : 2)
}
},
},
}
</script>
<style lang="scss" scoped>
.test-page {
min-height: 100vh;
background: #f8f9fa;
padding-bottom: 100px;
}
.test-content {
padding: 40rpx;
}
.test-title {
font-size: 36rpx;
font-weight: bold;
text-align: center;
color: #333;
margin-bottom: 40rpx;
}
.status-info {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
text {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
}
}
.icon-test {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
}
.icon-section {
margin-bottom: 40rpx;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.icon-row {
display: flex;
align-items: center;
gap: 20rpx;
}
.test-icon {
width: 60rpx;
height: 60rpx;
border: 2rpx solid #eee;
border-radius: 8rpx;
background: #f9f9f9;
}
.theme-switcher {
text-align: center;
}
.theme-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 50rpx;
padding: 20rpx 40rpx;
font-size: 28rpx;
font-weight: bold;
}
</style>

View File

@ -173,12 +173,12 @@ import areaProductList from '@/components/area-product-list/index.vue'
import { formatCurrency } from '@/util/index.js'
import { mapGetters } from 'vuex'
import RegionSelect from '@/components/region-select/index.vue'
import RaisedTabbar from '@/components/raised-tabbar.vue'
export default {
components: {
noticePopup,
znNewsPopup,
'cl-tabbar': clTabbar,
'cl-tabbar': RaisedTabbar,
getTree,
areaProductList,
RegionSelect,

View File

@ -349,6 +349,7 @@
</template>
<script>
import RaisedTabbar from '@/components/raised-tabbar.vue'
import clTabbar from '@/components/cl-tabbar.vue'
import * as min from '@/config/balance.js'
import * as api from '@/config/login.js'
@ -357,7 +358,7 @@ import RegionSelect from '@/components/region-select/index.vue'
export default {
components: {
'cl-tabbar': clTabbar,
'cl-tabbar': RaisedTabbar,
RegionSelect,
// talentList,
},

View File

@ -47,11 +47,12 @@ import { fansCode as getShareCode } from '@/config/goods'
import clTabbar from '@/components/cl-tabbar.vue'
import DefaultSharePage from '@/components/share/DefaultSharePage.vue'
import SpecialSharePage from '@/components/share/SpecialSharePage.vue'
import RaisedTabbar from '@/components/raised-tabbar.vue'
export default {
name: 'ShareQRCode',
components: {
'cl-tabbar': clTabbar,
'cl-tabbar': RaisedTabbar,
DefaultSharePage,
SpecialSharePage,
},
@ -214,24 +215,7 @@ export default {
.tabbar {
position: static;
bottom: 0;
z-index: 1000;
width: 100%;
height: 50px;
:v-deep .u-tabbar--fixed {
height: 100px !important;
}
}
@media screen and (max-height: 667px) {
.tabbar {
height: 70px !important;
}
}
@media screen and (min-height: 812px) {
.tabbar {
height: 80px !important;
}
}
</style>

View File

@ -181,9 +181,11 @@
<script>
import * as api from '@/config/goods'
import clTabbar from '@/components/cl-tabbar.vue'
import RaisedTabbar from '@/components/raised-tabbar.vue'
export default {
components: {
'cl-tabbar': clTabbar,
'cl-tabbar': RaisedTabbar,
},
data() {
return {

View File

@ -35,9 +35,10 @@ import * as apis from '@/config/index.js'
import clTabbar from '@/components/cl-tabbar.vue'
import * as ban from '@/config/balance.js'
import areaProductList from '@/components/area-product-list/index.vue'
import RaisedTabbar from '@/components/raised-tabbar.vue'
export default {
components: {
'cl-tabbar': clTabbar,
'cl-tabbar': RaisedTabbar,
'area-product-list': areaProductList,
},
data() {

1
static/images/code.svg Normal file
View File

@ -0,0 +1 @@
<svg t="1753425176636" class="icon" viewBox="65.5 65.5 893 893" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3699" width="256" height="256"><path d="M579.299 444.702h168.604V276.097H579.299v168.605z m84.302-120.765c20.137 0 36.463 16.325 36.463 36.462 0 20.137-16.326 36.462-36.463 36.462-20.138 0-36.462-16.325-36.462-36.462 0-20.138 16.324-36.462 36.462-36.462zM276.097 747.902h168.604V579.299H276.097v168.603z m84.302-120.763c20.137 0 36.462 16.324 36.462 36.462 0 20.137-16.325 36.463-36.462 36.463-20.137 0-36.461-16.326-36.461-36.463 0-20.138 16.324-36.462 36.461-36.462zM276.097 444.702h168.604V276.097H276.097v168.605z m84.302-120.765c20.137 0 36.462 16.325 36.462 36.462 0 20.137-16.325 36.462-36.462 36.462-20.137 0-36.461-16.325-36.461-36.462 0-20.138 16.324-36.462 36.461-36.462z" p-id="3700" fill="#f52a10"></path><path d="M512 65.5C265.405 65.5 65.5 265.405 65.5 512S265.405 958.5 512 958.5 958.5 758.595 958.5 512 758.595 65.5 512 65.5z m-21.657 708.201c0 10.959-8.885 19.844-19.844 19.844h-220.2c-10.959 0-19.844-8.885-19.844-19.844v-220.2c0-10.961 8.885-19.845 19.844-19.845h220.2c10.959 0 19.844 8.884 19.844 19.845v220.2z m0-303.202c0 10.959-8.885 19.844-19.844 19.844h-220.2c-10.959 0-19.844-8.885-19.844-19.844v-220.2c0-10.959 8.885-19.844 19.844-19.844h220.2c10.959 0 19.844 8.885 19.844 19.844v220.2z m203.385 323.046h-54.572v-59.074h54.572v59.074z m99.817-19.844c0 10.959-8.885 19.844-19.844 19.844h-30.362v-59.073h50.206v39.229z m0-88.84l-154.39-0.001v-37.69h-49.611v146.375h-36.043c-10.96 0-19.845-8.885-19.845-19.844v-220.2c0-10.961 8.885-19.845 19.845-19.845h140.227v98.603h49.611v-98.603h30.362c10.959 0 19.844 8.884 19.844 19.845v131.36z m0-214.362c0 10.959-8.885 19.844-19.844 19.844h-220.2c-10.96 0-19.845-8.885-19.845-19.844v-220.2c0-10.959 8.885-19.844 19.845-19.844h220.2c10.959 0 19.844 8.885 19.844 19.844v220.2z" p-id="3701" fill="#f52a10"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

169
static/images/qrcode-3d.svg Normal file
View File

@ -0,0 +1,169 @@
<svg width="120" height="120" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<!-- 定义强烈的3D效果和渐变 -->
<defs>
<!-- 强烈的3D背景渐变 -->
<radialGradient id="redBackground" cx="30%" cy="30%" r="80%">
<stop offset="0%" style="stop-color:#ff8888;stop-opacity:1" />
<stop offset="40%" style="stop-color:#ff4444;stop-opacity:1" />
<stop offset="80%" style="stop-color:#cc0000;stop-opacity:1" />
<stop offset="100%" style="stop-color:#880000;stop-opacity:1" />
</radialGradient>
<!-- 内圆3D效果 -->
<radialGradient id="innerCircle" cx="25%" cy="25%" r="75%">
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.9" />
<stop offset="30%" style="stop-color:#ffcccc;stop-opacity:0.7" />
<stop offset="70%" style="stop-color:#ff9999;stop-opacity:0.5" />
<stop offset="100%" style="stop-color:#ff6666;stop-opacity:0.3" />
</radialGradient>
<!-- 线条渐变效果 -->
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
<stop offset="50%" style="stop-color:#cccccc;stop-opacity:1" />
<stop offset="100%" style="stop-color:#888888;stop-opacity:1" />
</linearGradient>
<!-- 强烈外阴影 -->
<filter id="strongShadow" x="-50%" y="-50%" width="200%" height="200%">
<feDropShadow dx="5" dy="5" stdDeviation="4" flood-color="#000000" flood-opacity="0.6"/>
<feDropShadow dx="2" dy="2" stdDeviation="2" flood-color="#660000" flood-opacity="0.4"/>
</filter>
<!-- 内发光效果 -->
<filter id="innerGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<!-- 线条发光效果 -->
<filter id="lineGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="1" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<!-- 3D凸起效果 -->
<filter id="emboss" x="-50%" y="-50%" width="200%" height="200%">
<feConvolveMatrix order="3" kernelMatrix="
-2 -1 0
-1 1 1
0 1 2" result="emboss"/>
<feOffset dx="1" dy="1" result="offset"/>
<feFlood flood-color="#ffffff" flood-opacity="0.5"/>
<feComposite in2="offset" operator="in" result="emboss2"/>
<feMerge>
<feMergeNode in="emboss2"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<!-- 圆形裁剪 -->
<clipPath id="circleClip">
<circle cx="60" cy="60" r="48"/>
</clipPath>
</defs>
<!-- 最外层阴影圆 -->
<circle cx="63" cy="63" r="57" fill="#000000" opacity="0.3"/>
<!-- 主背景圆 - 强烈3D效果 -->
<circle cx="60" cy="60" r="55" fill="url(#redBackground)" filter="url(#strongShadow)"/>
<!-- 内圆 - 3D凹陷效果 -->
<circle cx="60" cy="60" r="48" fill="url(#innerCircle)" stroke="url(#lineGradient)" stroke-width="2" filter="url(#emboss)"/>
<!-- 二维码线条部分 -->
<g clip-path="url(#circleClip)" filter="url(#lineGlow)">
<!-- 左上角定位符 - 线条版本 -->
<g stroke="url(#lineGradient)" stroke-width="2.5" fill="none">
<circle cx="35" cy="35" r="12" opacity="0.9"/>
<circle cx="35" cy="35" r="8" opacity="0.8"/>
<circle cx="35" cy="35" r="4" opacity="0.7"/>
<circle cx="35" cy="35" r="1" fill="url(#lineGradient)" opacity="0.9"/>
</g>
<!-- 右上角定位符 - 线条版本 -->
<g stroke="url(#lineGradient)" stroke-width="2.5" fill="none">
<circle cx="85" cy="35" r="12" opacity="0.9"/>
<circle cx="85" cy="35" r="8" opacity="0.8"/>
<circle cx="85" cy="35" r="4" opacity="0.7"/>
<circle cx="85" cy="35" r="1" fill="url(#lineGradient)" opacity="0.9"/>
</g>
<!-- 左下角定位符 - 线条版本 -->
<g stroke="url(#lineGradient)" stroke-width="2.5" fill="none">
<circle cx="35" cy="85" r="12" opacity="0.9"/>
<circle cx="35" cy="85" r="8" opacity="0.8"/>
<circle cx="35" cy="85" r="4" opacity="0.7"/>
<circle cx="35" cy="85" r="1" fill="url(#lineGradient)" opacity="0.9"/>
</g>
<!-- 数据线条 - 环形分布 -->
<g stroke="url(#lineGradient)" stroke-width="2" fill="none" opacity="0.8">
<!-- 主要数据线条 -->
<path d="M 25,60 Q 35,35 60,25" stroke-width="1.5"/>
<path d="M 60,25 Q 85,35 95,60" stroke-width="1.5"/>
<path d="M 95,60 Q 85,85 60,95" stroke-width="1.5"/>
<path d="M 60,95 Q 35,85 25,60" stroke-width="1.5"/>
<!-- 交叉线条 -->
<path d="M 42,42 L 78,78" stroke-width="1"/>
<path d="M 78,42 L 42,78" stroke-width="1"/>
<!-- 环形线条 -->
<circle cx="60" cy="60" r="20" stroke-width="1" opacity="0.6"/>
<circle cx="60" cy="60" r="30" stroke-width="1" opacity="0.5"/>
<circle cx="60" cy="60" r="40" stroke-width="1" opacity="0.4"/>
</g>
<!-- 数据点线条 -->
<g stroke="url(#lineGradient)" stroke-width="1.5" fill="none" opacity="0.7">
<!-- 径向线条 -->
<line x1="60" y1="30" x2="60" y2="20" stroke-width="2"/>
<line x1="90" y1="60" x2="100" y2="60" stroke-width="2"/>
<line x1="60" y1="90" x2="60" y2="100" stroke-width="2"/>
<line x1="30" y1="60" x2="20" y2="60" stroke-width="2"/>
<!-- 对角线条 -->
<line x1="77" y1="43" x2="85" y2="35" stroke-width="1.5"/>
<line x1="77" y1="77" x2="85" y2="85" stroke-width="1.5"/>
<line x1="43" y1="77" x2="35" y2="85" stroke-width="1.5"/>
<line x1="43" y1="43" x2="35" y2="35" stroke-width="1.5"/>
<!-- 短线条装饰 -->
<line x1="50" y1="35" x2="55" y2="30"/>
<line x1="70" y1="35" x2="65" y2="30"/>
<line x1="85" y1="50" x2="90" y2="55"/>
<line x1="85" y1="70" x2="90" y2="65"/>
<line x1="70" y1="85" x2="65" y2="90"/>
<line x1="50" y1="85" x2="55" y2="90"/>
<line x1="35" y1="70" x2="30" y2="65"/>
<line x1="35" y1="50" x2="30" y2="55"/>
</g>
<!-- 中心对齐标记 - 线条版本 -->
<g stroke="url(#lineGradient)" stroke-width="2" fill="none" filter="url(#innerGlow)">
<circle cx="60" cy="60" r="6" opacity="0.9"/>
<circle cx="60" cy="60" r="3" opacity="0.8"/>
<circle cx="60" cy="60" r="1" fill="url(#lineGradient)" opacity="1"/>
<!-- 十字标记 -->
<line x1="54" y1="60" x2="66" y2="60" stroke-width="1"/>
<line x1="60" y1="54" x2="60" y2="66" stroke-width="1"/>
</g>
</g>
<!-- 强烈高光效果 -->
<ellipse cx="42" cy="35" rx="20" ry="6" fill="rgba(255,255,255,0.7)" transform="rotate(-35 42 35)" filter="url(#innerGlow)"/>
<ellipse cx="35" cy="42" rx="6" ry="20" fill="rgba(255,255,255,0.4)" transform="rotate(-35 35 42)"/>
<!-- 边缘高光 -->
<circle cx="60" cy="60" r="54" stroke="rgba(255,255,255,0.3)" stroke-width="1" fill="none"/>
<circle cx="60" cy="60" r="47" stroke="rgba(255,255,255,0.2)" stroke-width="1" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB