JS简单实现图片预览功能
给博客手写一个图片预览,顺便分享实现思路.
发现博客上没有图片放大查看的功能,很是不方便,遵循买不如造的> 原则,jquery.layer又那么大个,想着就两行代码的事性,为什么> 要去下载一个库呢.
JS实现图片预览
思路
- 点击小图片,copy一份到全屏,放大图片.
- 放一个遮罩屏,点击一下删除大图,再次展示小图.
就这么简单,以为分分钟就行完了.但是有点小坑.
- 图片宽高比不一样,怎么能完美适配那全屏呢?
- 页面滚去时,关闭后又不能回到原来图片位置,体验不好.
- 图片全屏后,不能不能设置透明度,看不到页面情况,黑乎乎的.
- 开始用事件包着事件,写起来简单,但有坑,如果出现异常情况就关不掉窗口了.
- 直接关闭大图,会有两张图片同时出现,体验不流畅.
实现
我通常都喜欢先写最终效果,再写逻辑.
样式
有三张比例不一样的图片
<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>
大概长这样的
第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的宽高,要么太宽,要么太高,要么变形.
width:auto,height:auto;
都没法令我们满意.有没有保持宽高比,自适应放大缩小的方法呢?
很多人都想到了,用JS获取原图的宽高比,都根据屏幕的宽高比,缩放.利用transform
来缩放. 想想就头疼. 还不如找个插件得了.
其实css3中自带一个css属性:object-fit
,轻松就能解决了.我们这里使用了的是.object-fit: contain
等比例以最短的那边全屏铺满.
#img-layer > img{
width: 100%;
height: 100%;
object-fit: contain;
}
看效果.
无论宽高比例都完美适配. 至从最核心的部分解决了.
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
尽量展示原图等比缩小.
补充一些细节:比如鼠标样式,黑边
黑边的处理:
具体参考 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 部分
- 给所有图片加点击事件
- 给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