给博客手写一个图片预览,顺便分享实现思路.
发现博客上没有图片放大查看的功能,很是不方便,遵循买不如造的> 原则,jquery.layer又那么大个,想着就两行代码的事性,为什么> 要去下载一个库呢.

JS实现图片预览

思路

  1. 点击小图片,copy一份到全屏,放大图片.
  2. 放一个遮罩屏,点击一下删除大图,再次展示小图.

就这么简单,以为分分钟就行完了.但是有点小坑.

  1. 图片宽高比不一样,怎么能完美适配那全屏呢?
  2. 页面滚去时,关闭后又不能回到原来图片位置,体验不好.
  3. 图片全屏后,不能不能设置透明度,看不到页面情况,黑乎乎的.
  4. 开始用事件包着事件,写起来简单,但有坑,如果出现异常情况就关不掉窗口了.
  5. 直接关闭大图,会有两张图片同时出现,体验不流畅.

实现

我通常都喜欢先写最终效果,再写逻辑.

样式

有三张比例不一样的图片

<article class="post-content">
    <p>方形的</p>
       <img src="./img/1001.jpeg" alt="方形的" srcset="">
   <p>竖状的</p>
        <img src="./img/1003.jpeg" alt="竖状的" srcset="">
   p>很宽的</p>
        <img src="./img/1004.jpeg" alt="很宽" srcset="">
</article>
<div id="img-layer">
 <img src="./img/1001.jpeg" alt="方形的" srcset="">
</div>

大概长这样的

2023-07-21T15:12:47.png

第1步: 写一个预览窗口样式

    #img-layer{
        position: fixed;
        z-index: 999;
        background: rgba(18, 18, 18, 0.65);
        width:100vw;
        height:100vh;
        top: 0;
        left: 0;
       overflow: hidden;
    }
    #img-layer > img{
        width: 100%;
        height: 100%;
    }

此时图片总是显示不全,无论我们怎么高速img的宽高,要么太宽,要么太高,要么变形.

2023-07-21T15:21:39.png

2023-07-21T15:23:37.png

width:auto,height:auto; 都没法令我们满意.有没有保持宽高比,自适应放大缩小的方法呢?

很多人都想到了,用JS获取原图的宽高比,都根据屏幕的宽高比,缩放.利用transform来缩放. 想想就头疼. 还不如找个插件得了.

其实css3中自带一个css属性:object-fit,轻松就能解决了.我们这里使用了的是.
object-fit: contain等比例以最短的那边全屏铺满.

#img-layer > img{
        width: 100%;
        height: 100%;
        object-fit: contain;
    }

看效果.

2023-07-21T15:32:53.png

2023-07-21T15:33:21.png

2023-07-21T15:34:27.png

无论宽高比例都完美适配. 至从最核心的部分解决了.

object-fit都有哪些属性值:
参考: https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit

  • contain: 不变形,不裁剪,框不铺满,图片显示全. (有黑边)
  • cover: 不变形,裁剪,铺满,图片显示不全
  • fill: 变形,不裁剪,铺满,图片显示全
  • none: 不变形,不裁剪,原图比例,可能铺不满,可能超出边
  • scale-down: contain或者none中的一种,不变形,不裁剪,不铺满,图片显示全.

图片展示,我们一般用contain或者scale-down,有什么区别呢? contain尽量放大图片到外框等比放大,scale-down尽量展示原图等比缩小.

补充一些细节:比如鼠标样式,黑边

黑边的处理:
2023-07-21T16:05:55.png

具体参考 background-clip的区别.
https://www.w3school.com.cn/cssref/pr_background-clip.asp
我们选择content-box这样背景才不会被padding和border影响.
注意: 图片也有背景的.

鼠标样式
实际放大缩小提示,就不用在浮层上面,加许多复杂的ico了.

cursor: zoom-out;
cursor: zoom-in;

图片居中
使用flex来居中:

#img-layer{
  ...
  display: flex;
  align-items: center;
  justify-content: center;
}

完整css部分

#img-layer{
    position: fixed;
    z-index: 999;
    inset: 0px;
    cursor: zoom-out;
    background: rgba(18, 18, 18, 0.65);
    will-change: opacity;
    visibility:hidden;
    width: 100vw;
    height:100vh;
   display: flex;
  align-items: center;
  justify-content: center;
}


#img-layer > img{
    inset: 0px;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: content-box;
}


@keyframes animation-zoom {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.post-content img{
    cursor: zoom-in;
    display: block;
    background-color: transparent;
    animation: animation-zoom 0.5s ease-in;
    max-height: 400px;
}

JS 部分

  1. 给所有图片加点击事件
  2. 给layer层加关闭事件
    let imgLayer=document.querySelector("#img-layer");
    if(!imgLayer){
        imgLayer=document.createElement("div");
        imgLayer.setAttribute("id","img-layer");
        document.documentElement.appendChild(imgLayer);
    }

// 浏览窗口
    const openLayer=function(event){
        const target=event.target
// clone一份
        cloneImg=target.cloneNode(true);

        // 隐藏原图
        target.style.visibility="hidden";
        target.style.opacity=0;
// 加个状态属性,方便查找
        target.setAttribute("layer-status","yes");

        // 加载大图
        imgLayer.style.visibility="visible"
        imgLayer.innerHTML="";
        cloneImg.visibility="visible";
        cloneImg.opacity=1;
        imgLayer.appendChild(cloneImg);

        // 监听滚动事件,关闭
        document.addEventListener("scroll",closeLayer);
    }

// 关闭窗口
    const closeLayer=function(e){
        const img=document.querySelector(".post-content img[layer-status='yes']");
        if(!img){
            return false;
        }
        img.style.visibility="visible";
        img.style.opacity=1;
        img.setAttribute("layer-status","no");

        imgLayer.style.visibility="hidden"
        imgLayer.innerHTML="";

        document.removeEventListener("scroll",closeLayer);
    }
    // 监听层关闭
    imgLayer.addEventListener("click",closeLayer);


    // 监听图片,打开
    const imgs=document.querySelectorAll(".post-content img");
    imgs && imgs.forEach(function(img){
        img.addEventListener("click",openLayer);
    })
};

完整效果

原作者:阿金
本文地址:https://hi-arkin.com/archives/js-img-views.html

标签: object-fit background-clip

(本篇完)

评论