music / src /components /layout /AppTabBar.vue
ahutchen's picture
refactor(search): 重构搜索功能并添加搜索历史页面
a1eddda
<template>
<div
class="app-tabbar"
v-show="!shouldHideTabbar"
>
<div class="tabbar-content">
<router-link
v-for="tab in tabs"
:key="tab.name"
:to="tab.path"
class="tab-item"
:class="{ active: currentRoute === tab.name }"
@click="handleTabClick(tab)"
>
<i :class="tab.icon" class="tab-icon"></i>
<span class="tab-label">{{ tab.label }}</span>
</router-link>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const tabs = [
{
name: 'Home',
path: '/home',
label: '首页',
icon: 'fas fa-home'
},
{
name: 'Favorites',
path: '/favorites',
label: '我喜欢',
icon: 'fas fa-heart'
},
{
name: 'Playlists',
path: '/playlists',
label: '歌单',
icon: 'fas fa-music'
},
{
name: 'PlayQueue',
path: '/play-queue',
label: '播放列表',
icon: 'fas fa-list'
}
]
const currentRoute = computed(() => route.name)
// 判断是否应该隐藏tabbar
const shouldHideTabbar = computed(() => {
return route.meta?.fullScreen || false
})
const handleTabClick = (tab) => {
// 触觉反馈(如果支持)
if (navigator.vibrate) {
navigator.vibrate(10)
}
}
</script>
<style scoped>
.app-tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--bg-card);
backdrop-filter: blur(20px);
border-top: 1px solid var(--border-strong);
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
/* iOS PWA 模式底部间距 */
@supports (-webkit-touch-callout: none) {
@media all and (display-mode: standalone) {
.app-tabbar {
padding-bottom: 20px;
}
}
}
.tabbar-content {
display: flex;
height: var(--tabbar-height);
max-width: 480px;
margin: 0 auto;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-decoration: none;
color: var(--text-disabled);
transition: var(--transition-fast);
min-height: var(--touch-target);
position: relative;
padding: 4px;
}
.tab-item:hover,
.tab-item.active {
color: var(--primary-color);
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 50%;
transform: translateX(-50%);
width: 24px;
height: 2px;
background: var(--primary-color);
border-radius: 1px;
/* 使用与进度条不同的视觉效果 */
box-shadow: 0 -1px 4px var(--glow-color);
opacity: 0.9;
}
.tab-icon {
font-size: 20px;
margin-bottom: 2px;
}
.tab-label {
font-size: 10px;
font-weight: 500;
line-height: 1;
}
/* 响应式适配 */
@media (max-width: 320px) {
.tab-label {
font-size: 9px;
}
.tab-icon {
font-size: 18px;
}
.app-tabbar {
border-top: 1px solid var(--border-strong);
}
}
/* PC端隐藏底部标签栏 */
@media (min-width: 1024px) {
.app-tabbar {
display: none;
}
}
</style>