掘金上面的图片预览 其中的transition 是复制过来的 transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) !important; 效果和下面2张图片差不多
思路
- 准备一个imgA,作动画效果(<img class="theP hiddenP">)
- 点击原本图片是,计算scale,以及设计left top居中,
- 遮罩层顶层放一个div,用于监听事件(点击,滑动)
- 点击/滑动时,imgA复位,然后display:none
html
<body style="margin: 0">
<div id="box" style="height: 100vh; overflow: auto">
<div style="height: 500px"></div>
<span>图片1</span>
<img class="topreview" src="./img/aaa.jpg" />
<div style="height: 500px"></div>
<span>图片2</span>
<img class="topreview" src="./img/img2.jpg" />
<div></div>
<div style="height: 500px"></div>
<img
class="theP hiddenP"
style="display: none"
class="hiddenP"
src="./img/1714029437897.jpg"
/>
<div class="bgmask"></div>
<div class="bgmask2"></div>
<div style="height: 500px"></div>
<div style="height: 500px"></div>
<div style="height: 500px"></div>
<div style="height: 500px"></div>
</div>
</body>
样式
<style>
.theP {
/* transition: 18s all; */
transform-origin: top left;
z-index: 100;
position: fixed;
transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) !important;
}
.bgmask {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.7);
opacity: 0.5;
display: none;
position: fixed;
z-index: 10;
top: 0;
left: 0;
}
.bgmask2 {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.7);
opacity: 0;
display: none;
position: fixed;
z-index: 200;
top: 0;
left: 0;
}
</style>
JS
const imgs = document.querySelectorAll(".topreview"); // 页面中的所有图片
const bigImg = document.querySelector(".hiddenP");// 预览图片
const bgmask = document.querySelector(".bgmask");//遮罩层
const bgmask2 = document.querySelector(".bgmask2");//遮罩层顶层 监听滑动事件和点击事件
const prex = document.body.clientHeight / document.body.clientWidth;
let topPreImge = 0;// 用于记录点击前 图片的位置
let current = null;
for (const img of imgs) {
img.onclick = function (e) {
current = this;// 正在预览的图片
const { left, top } = this.getBoundingClientRect();
topPreImge = top;// 用于记录点击前 图片的位置
const prexImg = this.clientHeight / this.clientWidth;
let scale = 1;
let trTop = "";
let trLeft = "";
if (prex < prexImg) {
//高度先撑满
scale = window.innerHeight / this.clientHeight;
trTop = -(top / scale);
const w = (window.innerWidth - scale * this.clientWidth) / 2;
trLeft = (w - left) / scale;
} else {
scale = window.innerWidth / this.clientWidth;
trLeft = -(left / scale);
const h = (window.innerHeight - scale * this.clientHeight) / 2;
trTop = (h - top) / scale;
}
//预览图片宽高不变
bigImg.style = `display:block;left:${left};top:${top};
height:${this.clientHeight}px;
width:${this.clientWidth}px;`;
bgmask.style = `display:block;`;
bgmask2.style = `display:block;`;
setTimeout(() => {
bigImg.style = `left:${left}px;top:${top}px;display:block;
height:${this.clientHeight}px;
width:${this.clientWidth}px;
transform:scale(${scale}) translate3d(${trLeft}px, ${trTop}px, 0px);
`;
current.style.visibility='hidden'
}, 100);//使用setTimeout transition不支持display:none
bigImg.src = this.src;
};
}
function clickBg() {
const { left, top } = current.getBoundingClientRect();
if (top == topPreImge) { // 位置不变
bigImg.style.transform = "";
} else { // 位置改变
bigImg.style.transform = `translate3d(0px,${
top - topPreImge // 复位
}px,0px)`;
}
bgmask.style.display = "none"; // 隐藏
bgmask2.style.display = "none"; // 隐藏
setTimeout(() => {
bigImg.style.display = "none"; // 使用setTimeout transition不支持display:none
current.style.visibility='visible'
}, 300);
}
bgmask2.onclick = clickBg;
let t = null;
bgmask2.onwheel = (e) => {
let h = e.wheelDelta;
if (h > 0) {
//向上滑动
box.scrollBy({
top: -500,
behavior: "smooth",
});
} else {
// 向下滑动
box.scrollBy({
top: 500,
behavior: "smooth",
});
}
clearTimeout(t); // 防抖
t = setTimeout(() => {
clickBg();
}, 300);
};