Почему эта анимация неверна? - PullRequest
0 голосов
/ 28 января 2019

Я пытаюсь реализовать таблицу (на данный момент основанную на 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>

1 Ответ

0 голосов
/ 28 января 2019

Я думаю, что проблема здесь в интерполяции.Вы предполагаете, что на каждом шаге анимации у нас всегда будут scale(x) и scale(1/x), где x в пределах [0,1], но из-за округления я не думаю, что у вас это будет.

Здесьэто базовый пример:

.box,
p{
 transform-origin:0 0;
 transition:1s linear;
}
.box:hover {
  transform:scale(0.1);
}
.box:hover p{
  transform:scale(10);
}
<div class="box">
<p>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
Lorem Ipsume<br>
</p>
</div>

Логически мы можем думать, что текст останется прежним, но нет.Оно будет расти, а затем снова уменьшаться.Так что да, весы будут отменены, но не во время анимации.

...