实现响应式图片查看器:轻量级lightbox解决方案

  Java   24分钟   1222浏览   0评论

你好呀,我是小邹。

在现代Web开发中,lightbox组件是一种常见的增强用户体验的方法,它允许用户在不离开当前页面的情况下查看和操作图片。本文将引导你构建一个轻量级的lightbox,具备基本的图片放大、缩小以及关闭功能,并且兼容桌面和移动设备。

引言

Lightbox不仅增强了网站的视觉吸引力,还提供了更流畅的用户交互体验。在本文中,我们将探讨如何创建一个简易但功能齐全的lightbox,包括:

  • 响应式设计,确保在不同设备上良好显示。
  • 图片的放大与缩小功能。
  • 使用CSS和JavaScript实现的平滑动画和交互。

效果图

image-20240708172614544

image-20240708172624899

准备工作

在开始之前,请确保你熟悉HTML、CSS和JavaScript的基本知识。我们的目标是创建一个可以嵌入任何网页的lightbox,无需引入额外的库或框架。

设计lightbox

首先,我们定义lightbox的HTML结构。它将包含一个用于显示图片的<img>元素,以及两个用于控制图片缩放的按钮。

<div id="lightbox" style="display:none;">
    <img id="lightboxImg">
    <button id="zoomIn" class="zoomButton">+</button>
    <button id="zoomOut" class="zoomButton">-</button>
</div>

接下来,我们编写CSS样式来美化lightbox并使其具有响应性。

#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%;
}

#lightbox .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; /* 平滑过渡效果 */
}

#lightbox .zoomButton:hover {
    background-color: rgba(255, 255, 255, 0.8); /* 鼠标悬停时加深背景色 */
}

#zoomIn {
    right: 10px;
}

#zoomOut {
    right: 60px;
}

实现交互逻辑

现在,我们通过JavaScript来实现lightbox的功能。我们将监听图片点击事件以显示lightbox,同时监听滚轮事件和按钮点击事件以调整图片的大小。

document.addEventListener('DOMContentLoaded', function () {
    // ...JavaScript代码...
});

显示lightbox

当用户点击任何图片时,lightbox应显示该图片。

var images = document.querySelectorAll('img');
images.forEach(function (image) {
    image.addEventListener('click', function (event) {
        lightboxImg.src = this.src;
        lightbox.style.display = 'flex';
    });
});

缩放功能

利用滚轮事件和按钮点击事件,我们可以轻松地增加或减少图片的缩放比例。

var scale = 1;

lightboxImg.addEventListener('wheel', function (event) {
    event.preventDefault();
    scale -= event.deltaY > 0 ? 0.1 : -0.1;
    scale = Math.min(Math.max(0.1, scale), 3);
    updateTransform();
}, { passive: false });

zoomInButton.addEventListener('click', function () {
    scale += 0.1;
    scale = Math.min(3, scale);
    updateTransform();
});

zoomOutButton.addEventListener('click', function () {
    scale -= 0.1;
    scale = Math.max(0.1, scale);
    updateTransform();
});

更新图片变换

我们需要一个辅助函数来更新图片的transform样式。

function updateTransform() {
    lightboxImg.style.transform = `scale(${scale})`;
}

关闭lightbox

最后,我们需要一个方法来关闭lightbox,当用户点击lightbox的背景时。

lightbox.addEventListener('click', function (event) {
    if (event.target === this) {
        lightbox.style.display = 'none';
    }
});

完整JavaScript代码

<script type="application/javascript">
    document.addEventListener('DOMContentLoaded', function () {
        var lightbox = document.getElementById('lightbox');
        var lightboxImg = document.getElementById('lightboxImg');
        var zoomInButton = document.getElementById('zoomIn');
        var zoomOutButton = document.getElementById('zoomOut');
        var scale = 1; // 图片缩放比例
        var offsetX = 0; // 图片水平偏移量
        var offsetY = 0; // 图片垂直偏移量
        var isDragging = false;
        var dragStartX, dragStartY;
        var lastTouchDistance = 0;

        // 初始化图片位置和缩放
        updateTransform();

        // 使用事件委托处理所有图片点击
        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')) {
                    return;
                }

                event.stopPropagation();
                lightboxImg.src = event.target.src;
                resetTransform();
                lightbox.style.display = 'flex';
            }
        });

        // 为lightbox添加点击事件处理器
        lightbox.addEventListener('click', function (event) {
            if (event.target === this || event.target === lightboxImg) {
                if (event.target === lightboxImg) {
                    resetTransform();
                    return;
                }
                lightbox.style.display = 'none';
            }
        });

        // 重置变换到默认值
        function resetTransform() {
            scale = 1;
            offsetX = 0;
            offsetY = 0;
            updateTransform();
            lightboxImg.style.transition = 'all 0.3s ease';
            setTimeout(() => {
                lightboxImg.style.transition = '';
            }, 300);
        }

        // 更新图片的transform样式
        function updateTransform() {
            lightboxImg.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
        }

        // 监听滚轮事件,实现图片缩放
        lightboxImg.addEventListener('wheel', function (event) {
            event.preventDefault();
            const delta = Math.sign(event.deltaY);
            scale = delta > 0 ? Math.max(0.1, scale - 0.1) : Math.min(3, scale + 0.1);
            updateTransform();
        }, {passive: false});

        // 为放大按钮添加事件处理器
        zoomInButton.addEventListener('click', function (event) {
            event.stopPropagation();
            scale = Math.min(3, scale + 0.2);
            updateTransform();
        });

        // 为缩小按钮添加事件处理器
        zoomOutButton.addEventListener('click', function (event) {
            event.stopPropagation();
            scale = Math.max(0.1, scale - 0.2);
            updateTransform();
        });

        // ================= 手机端优化 =================
        // 双指缩放处理
        lightboxImg.addEventListener('touchstart', function (event) {
            if (event.touches.length === 2) {
                // 计算双指初始距离
                const dx = event.touches[0].clientX - event.touches[1].clientX;
                const dy = event.touches[0].clientY - event.touches[1].clientY;
                lastTouchDistance = Math.sqrt(dx * dx + dy * dy);
            } else if (event.touches.length === 1) {
                // 单指拖动准备
                isDragging = true;
                dragStartX = event.touches[0].clientX - offsetX;
                dragStartY = event.touches[0].clientY - offsetY;
            }
        }, {passive: false});

        // 触摸移动处理
        lightboxImg.addEventListener('touchmove', function (event) {
            event.preventDefault();

            if (event.touches.length === 2) {
                // 双指缩放
                const dx = event.touches[0].clientX - event.touches[1].clientX;
                const dy = event.touches[0].clientY - event.touches[1].clientY;
                const touchDistance = Math.sqrt(dx * dx + dy * dy);

                // 平滑缩放因子 (0.01 比之前的 0.1 更平缓)
                const scaleFactor = 0.01;
                if (lastTouchDistance > 0) {
                    if (touchDistance > lastTouchDistance) {
                        scale = Math.min(3, scale + (touchDistance - lastTouchDistance) * scaleFactor);
                    } else {
                        scale = Math.max(0.1, scale - (lastTouchDistance - touchDistance) * scaleFactor);
                    }
                    updateTransform();
                }
                lastTouchDistance = touchDistance;

            } else if (event.touches.length === 1 && isDragging) {
                // 单指拖动 - 增加灵敏度 (1.8倍)
                const sensitivity = 1.8;
                offsetX = (event.touches[0].clientX - dragStartX) * sensitivity;
                offsetY = (event.touches[0].clientY - dragStartY) * sensitivity;
                updateTransform();
            }
        }, {passive: false});

        // 触摸结束处理
        lightboxImg.addEventListener('touchend', function () {
            isDragging = false;
            lastTouchDistance = 0;
        });

        // 边界限制 - 防止图片被拖出可视区域
        lightboxImg.addEventListener('transitionend', function () {
            const imgRect = lightboxImg.getBoundingClientRect();
            const containerRect = lightbox.getBoundingClientRect();

            // 计算边界
            const maxOffsetX = Math.max(0, (imgRect.width * scale - containerRect.width) / 2);
            const maxOffsetY = Math.max(0, (imgRect.height * scale - containerRect.height) / 2);

            // 应用边界限制
            if (Math.abs(offsetX) > maxOffsetX) {
                offsetX = offsetX > 0 ? maxOffsetX : -maxOffsetX;
            }
            if (Math.abs(offsetY) > maxOffsetY) {
                offsetY = offsetY > 0 ? maxOffsetY : -maxOffsetY;
            }

            if (scale === 1) {
                offsetX = 0;
                offsetY = 0;
            }

            updateTransform();
        });
    });
</script>

结论

通过上述步骤,我们成功创建了一个简单的lightbox,具备基本的图片预览、放大、缩小功能,同时具有优雅的外观和良好的用户体验。这个lightbox可以轻松地集成到任何网页项目中,无需依赖外部库,是一个完美的自定义解决方案。

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