图片画廊浏览(侧重 CSS 网格布局和模态框交互)

发布于:2025-07-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

图片画廊浏览

  • 响应式网格布局,自动适应不同屏幕宽度
  • 图片分类筛选功能
  • 点击图片弹出模态框查看大图
  • 支持键盘导航(左右箭头切换,ESC 关闭)
  • 悬停效果增强用户体验

 

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>风景图片画廊</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
    <style>
        .gallery-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
            gap: 1.5rem;
        }
        
        .gallery-item {
            position: relative;
            overflow: hidden;
            border-radius: 0.75rem;
            cursor: pointer;
            aspect-ratio: 4/3;
        }
        
        .gallery-item img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            transition: transform 0.5s ease;
        }
        
        .gallery-item:hover img {
            transform: scale(1.05);
        }
        
        .gallery-item::after {
            content: '';
            position: absolute;
            inset: 0;
            background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
            opacity: 0;
            transition: opacity 0.3s ease;
        }
        
        .gallery-item:hover::after {
            opacity: 1;
        }
        
        .gallery-caption {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            padding: 1.5rem;
            color: white;
            transform: translateY(20px);
            transition: transform 0.3s ease;
            z-index: 1;
        }
        
        .gallery-item:hover .gallery-caption {
            transform: translateY(0);
        }
        
        .modal {
            opacity: 0;
            visibility: hidden;
            transition: all 0.3s ease;
        }
        
        .modal.active {
            opacity: 1;
            visibility: visible;
        }
        
        .modal-content {
            transform: scale(0.95);
            transition: transform 0.3s ease;
        }
        
        .modal.active .modal-content {
            transform: scale(1);
        }
    </style>
</head>
<body class="bg-gray-100 font-sans">
    <header class="bg-white shadow-sm py-6">
        <div class="container mx-auto px-4">
            <h1 class="text-3xl font-bold text-gray-800 text-center">风景图片画廊</h1>
            <p class="text-gray-600 text-center mt-2">探索世界各地的美丽景色</p>
        </div>
    </header>

    <main class="container mx-auto px-4 py-10">
        <!-- 画廊过滤器 -->
        <div class="flex flex-wrap justify-center gap-3 mb-10">
            <button class="filter-btn active px-5 py-2 rounded-full bg-green-600 text-white" data-category="all">全部</button>
            <button class="filter-btn px-5 py-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors" data-category="mountains">山脉</button>
            <button class="filter-btn px-5 py-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors" data-category="oceans">海洋</button>
            <button class="filter-btn px-5 py-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors" data-category="forests">森林</button>
            <button class="filter-btn px-5 py-2 rounded-full bg-gray-200 hover:bg-gray-300 transition-colors" data-category="deserts">沙漠</button>
        </div>

        <!-- 图片画廊 -->
        <div class="gallery-grid">
            <!-- 图片项将通过JS动态生成 -->
        </div>
    </main>

    <!-- 模态框预览 -->
    <div id="image-modal" class="modal fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4">
        <div class="modal-content relative max-w-5xl w-full">
            <button id="close-modal" class="absolute -top-12 right-0 text-white text-2xl hover:text-gray-300 transition-colors">
                <i class="fa-solid fa-times"></i>
            </button>
            <button id="prev-btn" class="absolute left-4 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white w-10 h-10 rounded-full flex items-center justify-center transition-colors">
                <i class="fa-solid fa-chevron-left"></i>
            </button>
            <img id="modal-image" src="" alt="大图预览" class="w-full h-auto rounded-lg">
            <button id="next-btn" class="absolute right-4 top-1/2 -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white w-10 h-10 rounded-full flex items-center justify-center transition-colors">
                <i class="fa-solid fa-chevron-right"></i>
            </button>
            <div class="mt-4 text-white">
                <h3 id="modal-title" class="text-xl font-semibold"></h3>
                <p id="modal-desc" class="text-gray-300"></p>
            </div>
        </div>
    </div>

    <footer class="bg-gray-800 text-white py-8 mt-16">
        <div class="container mx-auto px-4 text-center">
            <p>© 2025 风景画廊 | 用HTML、CSS和JavaScript构建</p>
        </div>
    </footer>

    <script>
        // 画廊图片数据
        const galleryItems = [
            {
                id: 1,
                src: 'https://picsum.photos/id/29/800/600',
                thumbnail: 'https://picsum.photos/id/29/400/300',
                title: '山间云海',
                description: '清晨的山脉被云海环绕,宛如仙境',
                category: 'mountains'
            },
            {
                id: 2,
                src: 'https://picsum.photos/id/65/800/600',
                thumbnail: 'https://picsum.photos/id/65/400/300',
                title: '宁静海岸',
                description: '蓝色的海水拍打岸边,留下白色的浪花',
                category: 'oceans'
            },
            {
                id: 3,
                src: 'https://picsum.photos/id/137/800/600',
                thumbnail: 'https://picsum.photos/id/137/400/300',
                title: '茂密森林',
                description: '阳光透过树叶洒下,形成斑驳的光影',
                category: 'forests'
            },
            {
                id: 4,
                src: 'https://picsum.photos/id/10/800/600',
                thumbnail: 'https://picsum.photos/id/10/400/300',
                title: '沙漠日落',
                description: '夕阳下的沙漠呈现出温暖的金黄色',
                category: 'deserts'
            },
            {
                id: 5,
                src: 'https://picsum.photos/id/28/800/600',
                thumbnail: 'https://picsum.photos/id/28/400/300',
                title: '雪山之巅',
                description: '高耸的雪山直插云霄,壮丽非凡',
                category: 'mountains'
            },
            {
                id: 6,
                src: 'https://picsum.photos/id/76/800/600',
                thumbnail: 'https://picsum.photos/id/76/400/300',
                title: '热带海滩',
                description: '白色的沙滩和清澈的海水,度假胜地',
                category: 'oceans'
            },
            {
                id: 7,
                src: 'https://picsum.photos/id/129/800/600',
                thumbnail: 'https://picsum.photos/id/129/400/300',
                title: '迷雾森林',
                description: '清晨的森林被薄雾笼罩,神秘而宁静',
                category: 'forests'
            },
            {
                id: 8,
                src: 'https://picsum.photos/id/110/800/600',
                thumbnail: 'https://picsum.photos/id/110/400/300',
                title: '沙漠星空',
                description: '夜晚的沙漠,繁星满天,银河清晰可见',
                category: 'deserts'
            }
        ];

        // DOM元素
        const galleryGrid = document.querySelector('.gallery-grid');
        const filterBtns = document.querySelectorAll('.filter-btn');
        const modal = document.getElementById('image-modal');
        const modalImage = document.getElementById('modal-image');
        const modalTitle = document.getElementById('modal-title');
        const modalDesc = document.getElementById('modal-desc');
        const closeModal = document.getElementById('close-modal');
        const prevBtn = document.getElementById('prev-btn');
        const nextBtn = document.getElementById('next-btn');
        
        let currentImageIndex = 0;
        let filteredItems = [...galleryItems];

        // 初始化画廊
        renderGallery(galleryItems);

        // 渲染画廊
        function renderGallery(items) {
            galleryGrid.innerHTML = '';
            
            items.forEach((item, index) => {
                const galleryItem = document.createElement('div');
                galleryItem.className = 'gallery-item';
                galleryItem.dataset.category = item.category;
                galleryItem.dataset.index = index;
                
                galleryItem.innerHTML = `
                    <img src="${item.thumbnail}" alt="${item.title}">
                    <div class="gallery-caption">
                        <h3 class="font-semibold text-lg">${item.title}</h3>
                        <p class="text-sm text-gray-200">${item.description.substring(0, 30)}...</p>
                    </div>
                `;
                
                galleryItem.addEventListener('click', () => {
                    openModal(index);
                });
                
                galleryGrid.appendChild(galleryItem);
            });
        }

        // 打开模态框
        function openModal(index) {
            currentImageIndex = index;
            const item = filteredItems[index];
            
            modalImage.src = item.src;
            modalImage.alt = item.title;
            modalTitle.textContent = item.title;
            modalDesc.textContent = item.description;
            
            modal.classList.add('active');
            document.body.style.overflow = 'hidden';
        }

        // 关闭模态框
        function closeModalFunc() {
            modal.classList.remove('active');
            document.body.style.overflow = '';
        }

        // 下一张图片
        function nextImage() {
            currentImageIndex = (currentImageIndex + 1) % filteredItems.length;
            const item = filteredItems[currentImageIndex];
            
            modalImage.src = item.src;
            modalTitle.textContent = item.title;
            modalDesc.textContent = item.description;
        }

        // 上一张图片
        function prevImage() {
            currentImageIndex = (currentImageIndex - 1 + filteredItems.length) % filteredItems.length;
            const item = filteredItems[currentImageIndex];
            
            modalImage.src = item.src;
            modalTitle.textContent = item.title;
            modalDesc.textContent = item.description;
        }

        // 筛选功能
        filterBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                // 更新按钮样式
                filterBtns.forEach(b => {
                    b.classList.remove('active', 'bg-green-600', 'text-white');
                    b.classList.add('bg-gray-200', 'hover:bg-gray-300');
                });
                
                btn.classList.add('active', 'bg-green-600', 'text-white');
                btn.classList.remove('bg-gray-200', 'hover:bg-gray-300');
                
                // 筛选图片
                const category = btn.dataset.category;
                if (category === 'all') {
                    filteredItems = [...galleryItems];
                } else {
                    filteredItems = galleryItems.filter(item => item.category === category);
                }
                
                renderGallery(filteredItems);
            });
        });

        // 事件监听
        closeModal.addEventListener('click', closeModalFunc);
        nextBtn.addEventListener('click', nextImage);
        prevBtn.addEventListener('click', prevImage);
        
        // 点击模态框背景关闭
        modal.addEventListener('click', (e) => {
            if (e.target === modal) {
                closeModalFunc();
            }
        });
        
        // 键盘导航
        document.addEventListener('keydown', (e) => {
            if (!modal.classList.contains('active')) return;
            
            if (e.key === 'Escape') closeModalFunc();
            if (e.key === 'ArrowRight') nextImage();
            if (e.key === 'ArrowLeft') prevImage();
        });
    </script>
</body>
</html>

 


网站公告

今日签到

点亮在社区的每一天
去签到