feat: 重构底部导航栏为自定义矢量图标样式

这个提交包含在:
YuanWen
2026-11-02 14:20:51 +08:00
父节点 7ab7429dee
当前提交 1323b8877f

查看文件

@@ -3,40 +3,56 @@
<view class="tabbar">
<!-- 1. 首页 -->
<view class="tab" :class="{ on: current === 0 }" @tap="switchTab(0)">
<image class="tab-icon" :src="current === 0 ? ICONS.homeActive : ICONS.home" mode="aspectFit"></image>
<view class="tic">
<view class="tr" style="left:10rpx;top:4rpx"></view>
<view class="ol" style="left:13rpx;top:16rpx;width:18rpx;height:18rpx;border-top:none"></view>
</view>
<text class="tab-txt">首页</text>
</view>
<!-- 2. 订单 -->
<view class="tab" :class="{ on: current === 1 }" @tap="switchTab(1)">
<image class="tab-icon" :src="current === 1 ? ICONS.orderActive : ICONS.order" mode="aspectFit"></image>
<view class="tic">
<view class="ol" style="left:11rpx;top:5rpx;width:22rpx;height:30rpx;border-radius:3rpx"></view>
<view class="ln" style="left:16rpx;top:13rpx;width:12rpx;height:3rpx"></view>
<view class="ln" style="left:16rpx;top:21rpx;width:12rpx;height:3rpx"></view>
</view>
<text class="tab-txt">订单</text>
</view>
<!-- 3. 中间高光 FAB:立即下单 -->
<!-- 3. 中央上浮主按钮:立即下单 -->
<view class="tab tab-center">
<view class="fab-wrapper" @tap="onOrder">
<view class="fab clickable-hover">
<image class="fab-icon" :src="ICONS.plus" mode="aspectFit"></image>
<view class="fab" @tap="onOrder">
<view class="fic">
<view class="fo" style="left:5rpx;top:2rpx;width:32rpx;height:32rpx;border-radius:5rpx"></view>
<view class="fl" style="left:11rpx;top:11rpx;width:14rpx;height:3rpx"></view>
<view class="fl" style="left:11rpx;top:19rpx;width:14rpx;height:3rpx"></view>
<view class="fp" style="left:25rpx;top:22rpx;width:21rpx;height:6rpx"></view>
</view>
<text class="fab-label">立即下单</text>
<text class="fab-txt">立即下单</text>
</view>
</view>
<!-- 4. 消息 -->
<view class="tab" :class="{ on: current === 2 }" @tap="switchTab(2)">
<image class="tab-icon" :src="current === 2 ? ICONS.msgActive : ICONS.msg" mode="aspectFit"></image>
<view class="tic">
<view class="ol" style="left:6rpx;top:7rpx;width:32rpx;height:24rpx;border-radius:12rpx"></view>
<view class="tr-d" style="left:14rpx;top:29rpx"></view>
</view>
<text class="tab-txt">消息</text>
</view>
<!-- 5. 我的 -->
<view class="tab" :class="{ on: current === 3 }" @tap="switchTab(3)">
<image class="tab-icon" :src="current === 3 ? ICONS.mineActive : ICONS.mine" mode="aspectFit"></image>
<view class="tic">
<view class="ol ct" style="left:14rpx;top:3rpx;width:16rpx;height:16rpx"></view>
<view class="ol" style="left:7rpx;top:21rpx;width:30rpx;height:16rpx;border-radius:15rpx 15rpx 0 0;border-bottom:none"></view>
</view>
<text class="tab-txt">我的</text>
</view>
</view>
<!-- 底部防遮挡安全垫高 -->
<!-- 底部防遮挡垫高占位 -->
<view class="tabbar-placeholder"></view>
</view>
</template>
@@ -51,28 +67,6 @@
}
})
// 现代细腻矢量 SVG 图标集(双色品牌橙高质感)
const ICONS = {
// 首页
home: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E9297' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M3 9.5L12 3l9 6.5V20a1 1 0 0 1-1 1h-5v-6a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v6H4a1 1 0 0 1-1-1V9.5z'/></svg>",
homeActive: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23FFEADB' d='M4 10.2L12 4.3l8 5.9V19a1 1 0 0 1-1 1h-4v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5H5a1 1 0 0 1-1-1v-8.8z'/><path fill='%23F0710D' d='M12 3a1 1 0 0 1 .6.2l9 6.5a1 1 0 0 1-1.2 1.6L12 5.2 3.6 11.3a1 1 0 0 1-1.2-1.6l9-6.5A1 1 0 0 1 12 3zm-2 12h4v5h-4v-5z'/></svg>",
// 订单
order: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E9297' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/><polyline points='14 2 14 8 20 8'/><line x1='16' y1='13' x2='8' y2='13'/><line x1='16' y1='17' x2='8' y2='17'/><line x1='10' y1='9' x2='8' y2='9'/></svg>",
orderActive: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23FFEADB' d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/><path fill='%23F0710D' d='M14 2v6h6M8 13h8v2H8zm0 4h8v2H8zm0-8h3v2H8z'/></svg>",
// 中间加号
plus: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><line x1='12' y1='5' x2='12' y2='19'/><line x1='5' y1='12' x2='19' y2='12'/></svg>",
// 消息
msg: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E9297' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z'/></svg>",
msgActive: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23FFEADB' d='M20.5 11.5a8.5 8.5 0 0 1-12.3 7.6L3 21l1.9-5.2A8.5 8.5 0 1 1 20.5 11.5z'/><circle fill='%23F0710D' cx='8.5' cy='11.5' r='1.5'/><circle fill='%23F0710D' cx='12' cy='11.5' r='1.5'/><circle fill='%23F0710D' cx='15.5' cy='11.5' r='1.5'/></svg>",
// 我的
mine: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E9297' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/><circle cx='12' cy='7' r='4'/></svg>",
mineActive: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23FFEADB' d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/><circle fill='%23FFEADB' cx='12' cy='7' r='4'/><path fill='%23F0710D' d='M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm0 2c-3.3 0-8 1.7-8 5v2h16v-2c0-3.3-4.7-5-8-5z'/></svg>"
}
const TAB_ROUTES = [
'/pages/index/index',
'/pages/order/list',
@@ -102,114 +96,175 @@
}
</script>
<style scoped lang="scss">
<style scoped>
.yjyf-tabbar-container {
position: relative;
z-index: 99;
}
/* ---------- 自定义底部导航栏 (保持 content-box 避免被 safe-area 挤压高度) ---------- */
.tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 104rpx;
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(20px);
border-top: 1rpx solid rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
z-index: 99;
box-sizing: content-box !important;
height: 112rpx;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.03);
z-index: 100;
display: flex;
background: #ffffff;
box-shadow: 0 -6rpx 24rpx rgba(0, 0, 0, 0.07);
}
.tab {
flex: 1;
height: 112rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
transition: all 0.2s ease;
}
.tab-icon {
width: 44rpx;
height: 44rpx;
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
padding-bottom: 8rpx;
}
.tab-txt {
margin-top: 4rpx;
font-size: 20rpx;
color: #8E9297;
font-weight: 500;
letter-spacing: 0.5rpx;
transition: color 0.2s ease;
margin-top: 8rpx;
font-size: 22rpx;
line-height: 1.2;
color: #9A9A9A;
}
.tab.on .tab-txt {
color: #F0710D;
font-weight: 700;
font-weight: 600;
}
.tab.on .tab-icon {
transform: scale(1.06);
/* 底部图标定位容器 */
.tic {
position: relative;
width: 44rpx;
height: 40rpx;
flex-shrink: 0;
}
/* 中间 FAB:精致小圆纽 */
.tic view, .fic view {
position: absolute;
box-sizing: border-box;
}
.tic .ol {
position: absolute;
box-sizing: border-box;
border: 3rpx solid #9A9A9A;
border-radius: 3rpx;
}
.tic .ln {
position: absolute;
box-sizing: border-box;
background: #9A9A9A;
}
.tic .ct {
border-radius: 50%;
}
.tic .tr {
position: absolute;
box-sizing: border-box;
width: 0;
height: 0;
border-left: 11rpx solid transparent;
border-right: 11rpx solid transparent;
border-bottom: 11rpx solid #9A9A9A;
}
.tic .tr-d {
position: absolute;
box-sizing: border-box;
width: 0;
height: 0;
border-left: 7rpx solid transparent;
border-right: 7rpx solid transparent;
border-top: 7rpx solid #9A9A9A;
}
.tab.on .tic .ol {
border-color: #F0710D;
}
.tab.on .tic .ln {
background: #F0710D;
}
.tab.on .tic .tr {
border-bottom-color: #F0710D;
}
.tab.on .tic .tr-d {
border-top-color: #F0710D;
}
/* ---------- 中央上浮主按钮 ---------- */
.tab-center {
position: relative;
height: 112rpx;
overflow: visible;
}
.fab-wrapper {
position: relative;
top: -26rpx;
.fab {
position: absolute;
left: 50%;
top: -52rpx;
width: 128rpx;
height: 128rpx;
margin-left: -64rpx;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, #FFB65E 0%, #EE7412 100%);
box-shadow: 0 10rpx 26rpx rgba(238, 116, 18, 0.45);
}
.fab {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: linear-gradient(135deg, #FFA93F 0%, #F0710D 100%);
box-shadow: 0 6rpx 18rpx rgba(240, 113, 13, 0.32);
border: 4rpx solid #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.fab:active {
transform: scale(0.92);
box-shadow: 0 2rpx 10rpx rgba(240, 113, 13, 0.2);
}
.fab-icon {
.fic {
position: relative;
width: 44rpx;
height: 44rpx;
height: 36rpx;
flex-shrink: 0;
}
.fab-label {
margin-top: 6rpx;
font-size: 20rpx;
color: #F0710D;
font-weight: 600;
letter-spacing: 0.5rpx;
.fo {
position: absolute;
box-sizing: border-box;
border: 3rpx solid #ffffff;
border-radius: 5rpx;
}
/* 页面垫高高度 */
.fl {
position: absolute;
box-sizing: border-box;
background: #ffffff;
}
.fp {
position: absolute;
box-sizing: border-box;
background: #ffffff;
border-radius: 3rpx;
transform: rotate(-45deg);
}
.fab-txt {
margin-top: 4rpx;
font-size: 22rpx;
line-height: 1.2;
color: #ffffff;
}
/* 底部安全区占位 */
.tabbar-placeholder {
width: 100%;
height: 120rpx;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
height: calc(120rpx + constant(safe-area-inset-bottom));
height: calc(120rpx + env(safe-area-inset-bottom));
}
</style>