Я пытаюсь реализовать таблицу (на данный момент основанную на CSS-сетке) со скрытой строкой.При нажатии где-нибудь этот ряд должен плавно расширяться.Я хочу, чтобы содержимое этой строки было видимым и сохранило правильный размер во время анимации.
Это очень похоже на эту демонстрацию , но я не реализуюменю.Но тот факт, что в этой демонстрации содержимое («Пункт меню 1», «Пункт меню 2», ...) имеет постоянный размер во время анимации, является тем, чего я хочу.
Я хочу реализовать это с помощью Техника FLIP, как описано здесь для легкого достижения высокой частоты кадров.
Я добавил scaleY(0.01)
в строке и scaleY(100)
на внутренней оболочке, в надежде, что они отменити таким образом поддерживать масштаб.Я также добавил transform-origin: 0 0
, надеясь, что верхний край анимированной строки останется на том же месте во время анимации.
Однако в действительности содержимое слишком высокое.Они также движутся вдоль оси Y, даже когда я установил transform-origin: 0 0
(но это может быть просто следствием неправильной высоты).
Я пытался использовать Element.animate()
, а также ручную element.style.transform = ...
приближается, но безрезультатно.
Мой вопрос: почему скрытый ряд не анимирован должным образом (высота его содержимого не постоянна, и они, кажется, движутся вдоль оси Y)?Как это исправить?
let collapsed = Array.from(document.querySelectorAll(".collapsed"));
collapsed.forEach((row, idx) => {
row.dataset["collapsedIdx"] = idx;
document.querySelector("label").addEventListener("click", () => {
let collapsedSelf = row.getBoundingClientRect();
let rowsBelow = Array.from(
row.parentElement.querySelectorAll(`[data-collapsed-idx='${idx}'] ~ *`)
);
row.classList.remove("collapsed");
let expandedSelf = row.getBoundingClientRect();
let diffY = expandedSelf.height - collapsedSelf.height;
let animationTiming = {
duration: 2000,
easing: "linear"
};
let wrapper = row.querySelector(":scope > *");
row.animate(
[{ transform: `scaleY(0.01)` }, { transform: `scaleY(1)` }],
animationTiming
);
wrapper.animate(
[{ transform: `scaleY(100) ` },
{ transform: `scaleY(1) ` }],
animationTiming
);
rowsBelow.forEach((rowBelow) => {
rowBelow.animate([
{ transform: `translateY(-${diffY}px)` },
{ transform: `translateY(0)` }
], animationTiming);
});
});
});
* {
box-sizing: border-box;
}
section {
display: grid;
grid-template-columns: max-content 1fr;
}
.subsection {
grid-column: span 2;
}
label, p {
display: block;
margin: 0;
}
.collapsible,
.collapsible > * {
transform-origin: 0 0;
will-change: transform;
contain: content;
}
.collapsed {
height: 0;
overflow: hidden;
}
/* .collapsed {
transform: scaleY(.2);
}
.collapsed > * {
transform: scaleY(5)
}
*:nth-child(8),
*:nth-child(9),
*:nth-child(10),
*:nth-child(11),
*:nth-child(12) { transform: translateY(-35px); }
*/
/* .animate-on-transforms {
transition: transform 2000ms linear;
} */
<section>
<label><strong>CLICK ME!!!</strong></label>
<p>Value 1</p>
<label>Row 2</label>
<p>Value 2</p>
<label>Row 3</label>
<p>Value 3</p>
<div class="subsection collapsible collapsed">
<section>
<label>Subrow 1</label>
<p>Subvalue 1</p>
<label>Subrow 2</label>
<p>Subvalue 2</p>
<label>Subrow 3</label>
<p>Subvalue 3</p>
<label>Subrow 4</label>
<p>Subvalue 4</p>
</section>
</div>
<label>Row 4</label>
<p>Value 4</p>
<label>Row 5</label>
<p>Value 5</p>
</section>