从点击到滑动:博客图片浏览体验的进化与实现

  Java   19分钟   123浏览   0评论

你好呀,我是小邹。

在博客系统中,实现图片的左右翻动查看功能可以极大提升用户体验,让读者能够方便地浏览文章中的所有图片。本文将介绍如何实现这一功能,并详细解析相关代码。

示例图

功能需求分析

  • 点击文章中的图片后,弹出大图查看器
  • 支持左右翻动查看相邻图片
  • 支持缩放功能
  • 支持触摸滑动操作
  • 提供键盘导航支持

实现思路

  1. 收集文章中的所有图片
  2. 创建图片查看器组件
  3. 实现左右导航功能
  4. 添加缩放功能
  5. 支持触摸操作
  6. 添加键盘导航支持

核心代码实现

HTML结构

<!-- 图片查看器 -->
<div id="lightbox" style="display:none;">
    <img id="lightboxImg">
    <!-- 左右导航按钮 -->
    <button id="prevButton" class="navButton"></button>
    <button id="nextButton" class="navButton"></button>
    <!-- 放大缩小按钮 -->
    <button id="zoomIn" class="zoomButton"><i class="fa fa-search-plus"></i></button>
    <button id="zoomOut" class="zoomButton"><i class="fa fa-search-minus"></i></button>
</div>

CSS样式

#lightbox {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 9999;
}

#lightbox img {
    max-width: 90%;
    max-height: 90%;
}

/* 导航按钮样式 */
#prevButton, #nextButton {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background-color: rgba(255, 255, 255, 0.5);
    border: none;
    border-radius: 50%;
    color: #333;
    font-size: 24px;
    width: 50px;
    height: 50px;
    cursor: pointer;
    z-index: 10001;
    display: none; /* 默认隐藏 */
    transition: background-color 0.3s ease;
}

#prevButton:hover, #nextButton:hover {
    background-color: rgba(255, 255, 255, 0.8);
}

#prevButton {
    left: 20px;
}

#nextButton {
    right: 20px;
}

/* 放大缩小按钮 */
.zoomButton {
    position: absolute;
    bottom: 10px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    font-size: 24px;
    line-height: 40px;
    text-align: center;
    cursor: pointer;
    color: white;
    background-color: rgba(255, 255, 255, 0.5);
    border: none;
    transition: background-color 0.3s ease;
}

.zoomButton:hover {
    background-color: rgba(255, 255, 255, 0.8);
}

#zoomIn {
    bottom: 20px;
    right: 80px;
}

#zoomOut {
    bottom: 20px;
    right: 20px;
}

JavaScript核心逻辑

// 全局变量
let allArticleImages = []; // 存储文章内容区域的所有图片
let currentCommentImages = []; // 存储当前评论中的所有图片
let currentImageIndex = 0;

// 初始化文章图片
function initArticleImages() {
    const articleContent = document.getElementById('post-content');
    if (articleContent) {
        allArticleImages = Array.from(articleContent.querySelectorAll('img')).filter(img => {
            // 过滤掉不需要放大的图片
            return !img.classList.contains('emoji') &&
                !img.classList.contains('delete-btn') &&
                img.id !== 'lightboxImg' &&
                !img.closest('.avatar') &&
                !img.closest('a');
        });
    }
}

// 显示上一张图片
function showPrevImage() {
    if (currentImageIndex > 0) {
        currentImageIndex--;
        lightboxImg.src = currentCommentImages.length > 0 ?
            currentCommentImages[currentImageIndex].src :
            allArticleImages[currentImageIndex].src;
        resetTransform();
        updateNavButtons();
    }
}

// 显示下一张图片
function showNextImage() {
    const maxIndex = currentCommentImages.length > 0 ?
        currentCommentImages.length - 1 :
        allArticleImages.length - 1;

    if (currentImageIndex < maxIndex) {
        currentImageIndex++;
        lightboxImg.src = currentCommentImages.length > 0 ?
            currentCommentImages[currentImageIndex].src :
            allArticleImages[currentImageIndex].src;
        resetTransform();
        updateNavButtons();
    }
}

// 更新导航按钮状态
function updateNavButtons() {
    const imageCount = currentCommentImages.length > 0 ?
        currentCommentImages.length :
        allArticleImages.length;

    if (imageCount > 1) {
        prevButton.style.display = 'block';
        nextButton.style.display = 'block';

        const prevDisabled = currentImageIndex <= 0;
        const nextDisabled = currentImageIndex >= imageCount - 1;

        prevButton.disabled = prevDisabled;
        nextButton.disabled = nextDisabled;

        prevButton.style.opacity = prevDisabled ? '0.3' : '1';
        nextButton.style.opacity = nextDisabled ? '0.3' : '1';

        prevButton.style.cursor = prevDisabled ? 'not-allowed' : 'pointer';
        nextButton.style.cursor = nextDisabled ? 'not-allowed' : 'pointer';
    } else {
        prevButton.style.display = 'none';
        nextButton.style.display = 'none';
    }
}

// 图片点击事件处理
document.addEventListener('click', function (event) {
    if (event.target.tagName === 'IMG') {
        // 排除不需要放大的图片类型
        if (event.target.closest('#emoji-selector') ||
            event.target.classList.contains('delete-btn') ||
            event.target.id === 'lightboxImg' ||
            event.target.closest('.back-to-top') ||
            event.target.closest('.avatar') ||
            event.target.closest('a') ||
            event.target.closest('.comment-actions')) {
            return;
        }

        event.stopPropagation();

        // 处理文章图片
        if (allArticleImages.includes(event.target)) {
            currentCommentImages = [];
            for (let i = 0; i < allArticleImages.length; i++) {
                if (allArticleImages[i] === event.target) {
                    currentImageIndex = i;
                    break;
                }
            }
            lightboxImg.src = event.target.src;
            resetTransform();
            updateNavButtons();
            lightbox.style.display = 'flex';
        }
        // 其他图片处理逻辑...
    }
});

// 左右导航按钮事件
prevButton.addEventListener('click', function (event) {
    event.stopPropagation();
    if (!prevButton.disabled) {
        showPrevImage();
    }
});

nextButton.addEventListener('click', function (event) {
    event.stopPropagation();
    if (!nextButton.disabled) {
        showNextImage();
    }
});

// 键盘导航支持
document.addEventListener('keydown', function (event) {
    if (lightbox.style.display === 'flex') {
        switch (event.key) {
            case 'ArrowLeft':
                if (currentImageIndex > 0) {
                    showPrevImage();
                }
                event.preventDefault();
                break;
            case 'ArrowRight':
                const maxIndex = currentCommentImages.length > 0 ?
                    currentCommentImages.length - 1 :
                    allArticleImages.length - 1;
                if (currentImageIndex < maxIndex) {
                    showNextImage();
                }
                event.preventDefault();
                break;
            case 'Escape':
                lightbox.style.display = 'none';
                event.preventDefault();
                break;
        }
    }
});

// 初始化
document.addEventListener('DOMContentLoaded', function () {
    initArticleImages();
});

功能亮点

1. 智能图片收集

通过initArticleImages()函数,我们只收集文章内容区域的图片,并过滤掉不需要放大的图片(如表情、头像等)。

2. 平滑的导航体验

左右导航按钮会根据当前图片位置自动更新状态,当处于第一张或最后一张图片时,相应的按钮会变为不可用状态。

3. 多设备支持

  • 桌面设备:支持鼠标点击导航和键盘方向键导航
  • 移动设备:支持触摸滑动切换图片
  • 响应式设计:在不同屏幕尺寸下都能良好显示

4. 额外的实用功能

  • 图片缩放功能
  • 双击重置功能
  • ESC键关闭查看器

实现注意事项

  1. 性能优化:只收集需要放大的图片,避免不必要的内存占用
  2. 用户体验:添加平滑的过渡动画,提升视觉体验
  3. 可访问性:确保键盘导航支持,方便无障碍访问
  4. 错误处理:添加边界检查,防止索引越界

总结

通过实现博客文章内图片的左右翻动查看功能,为用户提供了更加便捷的图片浏览体验。该功能结合了现代化的UI设计和实用的交互功能,包括左右导航、缩放、触摸滑动和键盘支持等。实现的关键在于合理收集图片、管理当前图片索引,以及提供直观的导航界面。

这种图片查看器不仅适用于博客系统,也可以应用于任何需要展示多张图片的网站,如产品展示、相册等场景。通过进一步优化,还可以添加图片描述、下载功能等增强特性。

完整实现代码请参考文章开头提供的代码片段,可以根据实际需求进行调整和扩展。

如果你觉得文章对你有帮助,那就请作者喝杯咖啡吧☕
微信
支付宝
😀
😃
😄
😁
😆
😅
🤣
😂
🙂
🙃
😉
😊
😇
🥰
😍
🤩
😘
😗
☺️
😚
😙
🥲
😋
😛
😜
🤪
😝
🤑
🤗
🤭
🫢
🫣
🤫
🤔
🤨
😐
😑
😶
😏
😒
🙄
😬
😮‍💨
🤤
😪
😴
😷
🤒
🤕
🤢
🤮
🤧
🥵
🥶
🥴
😵
😵‍💫
🤯
🥳
🥺
😠
😡
🤬
🤯
😈
👿
💀
☠️
💩
👻
👽
👾
🤖
😺
😸
😹
😻
😼
😽
🙀
😿
😾
👋
🤚
🖐️
✋️
🖖
🫱
🫲
🫳
🫴
🫷
🫸
👌
🤌
🤏
✌️
🤞
🫰
🤟
🤘
🤙
👈️
👉️
👆️
🖕
👇️
☝️
🫵
👍️
👎️
✊️
👊
🤛
🤜
👏
🙌
👐
🤲
🤝
🙏
✍️
💅
🤳
💪
🦾
🦿
🦵
🦶
👂
🦻
👃
👶
👧
🧒
👦
👩
🧑
👨
👩‍🦱
👨‍🦱
👩‍🦰
👨‍🦰
👱‍♀️
👱‍♂️
👩‍🦳
👨‍🦳
👩‍🦲
👨‍🦲
🧔‍♀️
🧔‍♂️
👵
🧓
👴
👲
👳‍♀️
👳‍♂️
🧕
👮‍♀️
👮‍♂️
👷‍♀️
👷‍♂️
💂‍♀️
💂‍♂️
🕵️‍♀️
🕵️‍♂️
👩‍⚕️
👨‍⚕️
👩‍🌾
👨‍🌾
👩‍🍳
👨‍🍳
🐶
🐱
🐭
🐹
🐰
🦊
🐻
🐼
🐨
🐯
🦁
🐮
🐷
🐸
🐵
🐔
🐧
🐦
🦅
🦉
🐴
🦄
🐝
🪲
🐞
🦋
🐢
🐍
🦖
🦕
🐬
🦭
🐳
🐋
🦈
🐙
🦑
🦀
🦞
🦐
🐚
🐌
🐛
🦟
🪰
🪱
🦗
🕷️
🕸️
🦂
🦎
🐊
🐉
🐘
🦏
🦛
🐪
🐫
🦒
🦘
🦬
🐃
🐂
🐄
🐎
🐖
🐏
🐑
🐐
🦌
🐕
🐩
🦮
🐕‍🦺
🐈
🐈‍⬛
🐓
🦃
🦚
🦜
🦢
🦩
🕊️
🐇
🦝
🦨
🦡
🦫
🦦
🦥
🐁
🐀
🐿️
🦔
🌵
🎄
🌲
🌳
🌴
🌱
🌿
☘️
🍀
🎍
🎋
🍃
🍂
🍁
🍄
🌾
💐
🌷
🌹
🥀
🌺
🌸
🌼
🌻
🌞
🌝
🌛
🌜
🌚
🌕
🌖
🌗
🌘
🌑
🌒
🌓
🌔
🌙
🌎
🌍
🌏
🪐
💫
🌟
🔥
💥
☄️
☀️
🌤️
🌥️
🌦️
🌧️
⛈️
🌩️
🌨️
❄️
☃️
🌬️
💨
💧
💦
🌊
🍇
🍈
🍉
🍊
🍋
🍌
🍍
🥭
🍎
🍏
🍐
🍑
🍒
🍓
🥝
🍅
🥥
🥑
🍆
🥔
🥕
🌽
🌶️
🥒
🥬
🥦
🧄
🧅
🍄
🥜
🍞
🥐
🥖
🥨
🥯
🥞
🧇
🧀
🍖
🍗
🥩
🥓
🍔
🍟
🍕
🌭
🥪
🌮
🌯
🥙
🧆
🥚
🍳
🥘
🍲
🥣
🥗
🍿
🧈
🧂
🥫
🍱
🍘
🍙
🍚
🍛
🍜
🍝
🍠
🍢
🍣
🍤
🍥
🥮
🍡
🥟
🥠
🥡
🦪
🍦
🍧
🍨
🍩
🍪
🎂
🍰
🧁
🥧
🍫
🍬
🍭
🍮
🍯
🍼
🥛
🍵
🍶
🍾
🍷
🍸
🍹
🍺
🍻
🥂
🥃
🥤
🧃
🧉
🧊
🗺️
🏔️
⛰️
🌋
🏕️
🏖️
🏜️
🏝️
🏞️
🏟️
🏛️
🏗️
🏘️
🏙️
🏚️
🏠
🏡
🏢
🏣
🏤
🏥
🏦
🏨
🏩
🏪
🏫
🏬
🏭
🏯
🏰
💒
🗼
🗽
🕌
🛕
🕍
⛩️
🕋
🌁
🌃
🏙️
🌄
🌅
🌆
🌇
🌉
🎠
🎡
🎢
💈
🎪
🚂
🚃
🚄
🚅
🚆
🚇
🚈
🚉
🚊
🚝
🚞
🚋
🚌
🚍
🚎
🚐
🚑
🚒
🚓
🚔
🚕
🚖
🚗
🚘
🚙
🚚
🚛
🚜
🏎️
🏍️
🛵
🦽
🦼
🛺
🚲
🛴
🛹
🚏
🛣️
🛤️
🛢️
🚨
🚥
🚦
🚧
🛶
🚤
🛳️
⛴️
🛥️
🚢
✈️
🛩️
🛫
🛬
🪂
💺
🚁
🚟
🚠
🚡
🛰️
🚀
🛸
🧳
📱
💻
⌨️
🖥️
🖨️
🖱️
🖲️
💽
💾
📀
📼
🔍
🔎
💡
🔦
🏮
📔
📕
📖
📗
📘
📙
📚
📓
📒
📃
📜
📄
📰
🗞️
📑
🔖
🏷️
💰
💴
💵
💶
💷
💸
💳
🧾
✉️
📧
📨
📩
📤
📥
📦
📫
📪
📬
📭
📮
🗳️
✏️
✒️
🖋️
🖊️
🖌️
🖍️
📝
📁
📂
🗂️
📅
📆
🗒️
🗓️
📇
📈
📉
📊
📋
📌
📍
📎
🖇️
📏
📐
✂️
🗃️
🗄️
🗑️
🔒
🔓
🔏
🔐
🔑
🗝️
🔨
🪓
⛏️
⚒️
🛠️
🗡️
⚔️
🔫
🏹
🛡️
🔧
🔩
⚙️
🗜️
⚗️
🧪
🧫
🧬
🔬
🔭
📡
💉
🩸
💊
🩹
🩺
🚪
🛏️
🛋️
🪑
🚽
🚿
🛁
🧴
🧷
🧹
🧺
🧻
🧼
🧽
🧯
🛒
🚬
⚰️
⚱️
🗿
🏧
🚮
🚰
🚹
🚺
🚻
🚼
🚾
🛂
🛃
🛄
🛅
⚠️
🚸
🚫
🚳
🚭
🚯
🚱
🚷
📵
🔞
☢️
☣️
❤️
🧡
💛
💚
💙
💜
🖤
💔
❣️
💕
💞
💓
💗
💖
💘
💝
💟
☮️
✝️
☪️
🕉️
☸️
✡️
🔯
🕎
☯️
☦️
🛐
🆔
⚛️
🉑
☢️
☣️
📴
📳
🈶
🈚
🈸
🈺
🈷️
✴️
🆚
💮
🉐
㊙️
㊗️
🈴
🈵
🈹
🈲
🅰️
🅱️
🆎
🆑
🅾️
🆘
🛑
💢
💯
💠
♨️
🚷
🚯
🚳
🚱
🔞
📵
🚭
‼️
⁉️
🔅
🔆
🔱
⚜️
〽️
⚠️
🚸
🔰
♻️
🈯
💹
❇️
✳️
🌐
💠
Ⓜ️
🌀
💤
🏧
🚾
🅿️
🈳
🈂️
🛂
🛃
🛄
🛅
  0 条评论