00:00:00
相册
创建相册组件,该组件使用到了tailwindcss需要先安装,否则样式无法生效
vue
<template>
<div class="photo-gallery">
<h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-center mb-8 text-gray-800">我的相册</h2>
<div class="flex flex-wrap justify-center gap-3 mb-8">
<button
v-for="category in categories"
:key="category"
:class="[
'px-4 py-2 rounded-full transition-all duration-300',
activeCategory === category
? 'bg-blue-500 text-white' // 选中状态:蓝色背景 + 白色文字
: 'bg-gray-100 text-gray-700 hover:bg-gray-200' // 未选中状态
]"
@click="activeCategory = category"
>
{{ category }}
</button>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-6">
<div
v-for="(photo, index) in filteredPhotos"
:key="photo.id || index"
class="content-auto group cursor-pointer overflow-hidden rounded-lg shadow-md transition-all duration-300 hover:shadow-xl"
@click="openGallery(index)"
>
<div class="relative aspect-[5/3] overflow-hidden">
<img
:src="photo.thumbnail || photo.src"
:alt="photo.alt"
class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
loading="lazy"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-end p-4">
<h3 class="text-white font-medium text-lg">{{ photo.title || '未命名' }}</h3>
<p class="text-white/80 text-sm mt-1">{{ photo.description || '' }}</p>
</div>
</div>
</div>
</div>
<my-vue-picture-swipe
v-if="showGallery"
:items="photos"
:options="galleryOptions"
:initial-index="currentIndex"
@close="showGallery = false"
/>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import MyVuePictureSwipe from './MyVuePictureSwipe.vue';
import {photos} from './PhotoGalleryData';
// 响应式数据
const showGallery = ref(false);
const activeCategory = ref('全部');
const currentIndex = ref(0);
// 计算属性
const filteredPhotos = computed(() => {
if (activeCategory.value === '全部') {
return photos.value;
}
return photos.value.filter(photo => photo.category === activeCategory.value);
});
const categories = computed(() => {
const categories = new Set(photos.value.map(photo => photo.category));
return ['全部', ...Array.from(categories)];
});
// 配置选项
const galleryOptions = ref({
showHideAnimationType: 'fade',
bgOpacity: 0.9,
spacing: 0.1,
loop: true,
pinchToClose: true,
clickToCloseNonZoomable: true,
history: false,
indexIndicatorSep: ' / ',
getThumbBoundsFn: null
});
// 方法
const openGallery = (index) => {
console.log('openGallery', index)
currentIndex.value = index;
showGallery.value = true;
};
</script>
<style scoped>
.photo-gallery {
padding: 2rem 1rem;
max-width: 1400px;
margin: 0 auto;
}
:root {
--primary: #3b82f6;
}
.vue-picture-swipe__caption {
background: rgba(0, 0, 0, 0.7);
padding: 1rem;
text-align: center;
}
.vue-picture-swipe__caption-title {
font-size: 1.2rem;
font-weight: bold;
color: white;
}
.vue-picture-swipe__caption-description {
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.8);
margin-top: 0.5rem;
}
</style>