| <template> |
| <div class="empty-container"> |
| <div class="empty-content"> |
| |
| <div class="empty-icon"> |
| <i :class="iconClass"></i> |
| </div> |
| |
| |
| <h3 class="empty-title">{{ title }}</h3> |
| |
| |
| <p class="empty-description" v-if="description">{{ description }}</p> |
| |
| |
| <div class="empty-actions" v-if="$slots.action"> |
| <slot name="action"></slot> |
| </div> |
| </div> |
| </div> |
| </template> |
| |
| <script setup> |
| import { computed } from 'vue' |
| |
| const props = defineProps({ |
| |
| title: { |
| type: String, |
| default: '暂无内容' |
| }, |
| |
| |
| description: { |
| type: String, |
| default: '' |
| }, |
| |
| |
| type: { |
| type: String, |
| default: 'default', |
| validator: (value) => ['default', 'search', 'music', 'favorite', 'history', 'network'].includes(value) |
| } |
| }) |
| |
| |
| const iconClass = computed(() => { |
| const iconMap = { |
| default: 'fas fa-inbox', |
| search: 'fas fa-search', |
| music: 'fas fa-music', |
| favorite: 'fas fa-heart-broken', |
| history: 'fas fa-history', |
| network: 'fas fa-wifi' |
| } |
| |
| return iconMap[props.type] || iconMap.default |
| }) |
| </script> |
| |
| <style scoped> |
| .empty-container { |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| min-height: 200px; |
| padding: 40px 20px; |
| } |
| |
| .empty-content { |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| text-align: center; |
| max-width: 300px; |
| } |
| |
| .empty-icon { |
| margin-bottom: 20px; |
| } |
| |
| .empty-icon i { |
| font-size: 64px; |
| color: var(--text-tertiary); |
| opacity: 0.6; |
| } |
| |
| .empty-title { |
| font-size: 18px; |
| font-weight: 600; |
| color: var(--text-primary); |
| margin: 0 0 8px 0; |
| line-height: 1.4; |
| } |
| |
| .empty-description { |
| font-size: 14px; |
| color: var(--text-secondary); |
| margin: 0 0 24px 0; |
| line-height: 1.5; |
| } |
| |
| .empty-actions { |
| display: flex; |
| gap: 12px; |
| flex-wrap: wrap; |
| justify-content: center; |
| } |
| |
| |
| @media (max-width: 375px) { |
| .empty-container { |
| min-height: 160px; |
| padding: 30px 16px; |
| } |
| |
| .empty-icon i { |
| font-size: 48px; |
| } |
| |
| .empty-title { |
| font-size: 16px; |
| } |
| |
| .empty-description { |
| font-size: 13px; |
| margin-bottom: 20px; |
| } |
| } |
| |
| |
| .empty-content { |
| animation: fadeInUp 0.6s ease-out; |
| } |
| |
| @keyframes fadeInUp { |
| from { |
| opacity: 0; |
| transform: translateY(20px); |
| } |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| |
| |
| .empty-icon .fa-search { |
| color: #3182ce; |
| } |
| |
| .empty-icon .fa-music { |
| color: var(--accent-red); |
| } |
| |
| .empty-icon .fa-heart-broken { |
| color: #e53e3e; |
| } |
| |
| .empty-icon .fa-history { |
| color: #805ad5; |
| } |
| |
| .empty-icon .fa-wifi { |
| color: #38a169; |
| } |
| </style> |