gpt4 book ai didi

javascript - 平滑动画图像位置和缩放以适应 HTML/CSS 中的屏幕

转载 作者:行者123 更新时间:2023-12-01 15:55:26 25 4
gpt4 key购买 nike

我想在单击以填满整个屏幕时为图像制作动画,以便从其原始位置无缝过渡到其全尺寸,然后再返回,like on Medium.

这里的问题是 CSS position 属性,topleftis not animatable .尝试之后,我想到了使用 transform: scale() 属性,但这会导致一堆计算,我想尽可能避免这些计算。

我的复杂解决方案是使用 getBoundingClientRect() 获取元素的原始位置,并从那里找到图像必须位于的结束位置,并在每次图像被吹散时创建自定义动画使用 Element.animate 调整为全尺寸。我不确定这是解决此问题的最佳方法,因为计算出图像的最终大小和位置将是一些额外的数学运算,我真的不想搞砸。

下面是我当前的标记,一些 CSS 显示可以使用 translateX()translateY() 为位置动画设置关键帧,但不是我真正需要的.

document.querySelector('picture').onclick = function () {
document.querySelector('picture').classList.toggle('modal')
}
<style>
figure {
margin: 0 0 0 0;
display: inline-block; /* Stays same width as image contents */
background-color: whitesmoke;
}

img {
max-width: 100%; /* Images should fit within their container by default */
height: auto;
background-color: lightgrey;
margin: auto;
}

picture.modal {
position: fixed;
top: 0;
left: 0;
background-color: black;
height: 100vh;
width: 100vw;
margin: 0 0;
display: flex;
align-content: center;
object-fit: contain;
}
picture.modal img {
animation-name: slidein;
animation-duration: 1s;
}

@keyframes slidein {
0% {
transform: translateX(30px);
}
100% {
transform: translateX(0);
}
}

figcaption {
padding: 8px; /* Matches default page margin for Chrome/Edge */
}
</style>
<figure>
<picture>
<img src="https://c.pxhere.com/images/12/30/5e283733ff3cd2bd18d7cc13f40a-1435525.jpg!d" loading="auto" />
</picture>
<figcaption>
<header>Title</header>
<footer>Description</footer>
</figcaption>
</figure>

我开始按如下所示删除一些代码,但很快意识到另一个解决方案可能会好得多。

// Get the position of elements for animation
let x = document.querySelector('img').getBoundingClientRect().x
let y = document.querySelector('img').getBoundingClientRect().y

// Set the animation on the image so that it moves smoothly from its position outwards

如果知道一个 vanilla CSS 解决方案,我们将不胜感激。

最佳答案

您使用 getBoundingClientRect 的方向是正确的。通过使用它并对其应用一些计算,我能够想出这个

let imageResizing = false;

function zoomUnzoomImage(resizeEvent) {
if (!resizeEvent && this.classList.contains('zoomed')) {
this.classList.remove('zoomed');
this.style.transform = "";
document.querySelector('.image-backdrop').classList.remove('zoomed');
removeZoomOutListeners();
removeResizeListener();

} else {
let imageCordinates
if (resizeEvent) {
imageCordinates = this._originalImageCordinates;
}
else {
imageCordinates = getBoundingClientRect(this);
this._originalImageCordinates = imageCordinates;
}

const deviceRatio = window.innerHeight / window.innerWidth;
const imageRatio = imageCordinates.height / imageCordinates.width;

// Scale image according to the device and image size
const imageScale = deviceRatio > imageRatio ?
window.innerWidth / imageCordinates.width :
window.innerHeight / imageCordinates.height;

const imageX = ((imageCordinates.left + (imageCordinates.width) / 2));
const imageY = ((imageCordinates.top + (imageCordinates.height) / 2));

const bodyX = (window.innerWidth) / 2;
const bodyY = (window.innerHeight) / 2;


const xOffset = (bodyX - imageX) / (imageScale);
const yOffset = (bodyY - imageY) / (imageScale);


this.style.transform = "scale(" + imageScale + ") translate(" + xOffset + "px," + yOffset + "px) ";
this.classList.add('zoomed');
document.querySelector('.image-backdrop').classList.add('zoomed');
registersZoomOutListeners();
registerResizeListener();
}
}

function registersZoomOutListeners() {
// zoom out on scroll
document.addEventListener('scroll', scrollZoomOut);
// zoom out on escape
document.addEventListener('keyup', escapeClickZoomOut);
// zoom out on clicking the backdrop
document.querySelector('.image-backdrop').addEventListener('click', backDropClickZoomOut);
}

function removeZoomOutListeners() {
document.removeEventListener('scroll', scrollZoomOut);
document.removeEventListener('keyup', escapeClickZoomOut);
document.querySelector('.image-backdrop').removeEventListener('click', backDropClickZoomOut);
}

function registerResizeListener() {
window.addEventListener('resize', onWindowResize)
}

function removeResizeListener() {
window.removeEventListener('resize', onWindowResize)
}

function scrollZoomOut() {
if (document.querySelector('.zoomable-image.zoomed') && !imageResizing) {
zoomUnzoomImage.call(document.querySelector('.zoomable-image.zoomed'));
}
}

function backDropClickZoomOut() {
if (document.querySelector('.zoomable-image.zoomed')) {
zoomUnzoomImage.call(document.querySelector('.zoomable-image.zoomed'));
}
}

function escapeClickZoomOut(event) {
if (event.key === "Escape" && document.querySelector('.zoomable-image.zoomed')) {
zoomUnzoomImage.call(document.querySelector('.zoomable-image.zoomed'));
}
}

function onWindowResize() {
imageResizing = true;
if (document.querySelector('.zoomable-image.zoomed')) {
debounce(
function () {
zoomUnzoomImage.call(document.querySelector('.zoomable-image.zoomed'), true)
imageResizing = false;
}, 100)()
}
}

function getBoundingClientRect(element) {
var rect = element.getBoundingClientRect();
return {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
width: rect.width,
height: rect.height,
x: rect.x,
y: rect.y
};
}
function debounce(func, delay) {
let debounceTimer
return function () {
const context = this
const args = arguments
clearTimeout(debounceTimer)
debounceTimer
= setTimeout(() => func.apply(context, args), delay)
}
}

document.addEventListener('click', function (event) {
if (event && event.target && event.target.className.includes('zoomable-image')) {
zoomUnzoomImage.call(event.target)
}
});
figure {
margin: 0 0 0 0;
display: inline-block;
/* Stays same width as image contents */
background-color: whitesmoke;
}

img {
max-width: 100%;
/* Images should fit within their container by default */
height: auto;
background-color: lightgrey;
margin: auto;
transition: transform 0.3s;
}

.zoomable-image {
cursor: zoom-in;
}

.zoomable-image.zoomed {
cursor: zoom-out;
z-index: 100;
position: relative;
}

.image-backdrop.zoomed {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 50;
background-color: rgba(255, 255, 255, 0.95);
}
<div class="image-grid">
<img class="zoomable-image" src="https://picsum.photos/200/400?random=1" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/400/200?random=2" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/600/200?random=3" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/600/100?random=3" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/100/400?random=4" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/400/100?random=5" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/1000?random=6" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/300/400?random=7" loading="auto" />
<img class="zoomable-image" src="https://picsum.photos/400/300?random=8" loading="auto" />
</div>

<div class="image-backdrop"></div>

关于javascript - 平滑动画图像位置和缩放以适应 HTML/CSS 中的屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62975587/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com