Триггер и обратный переход CSS с Javascript - PullRequest
0 голосов
/ 27 января 2020

В настоящее время я изучаю возможности технологии FLIP , которая уменьшает все CSS переходы только до transform и opacity (из-за ускорения GPU). Это включает в себя манипулирование стилями непосредственно с Javascript. Хотя инициировать такой переход не очень сложно, я не смог его изменить. Обычно переход, определенный в пределах CSS, например при наведении, автоматически отменяется, когда вы прекращаете зависать. Но CSS недостаточно для запуска (и обратного) перехода по щелчкам. Я хочу быть в состоянии сделать следующее:

a) Нажмите на элемент (и запустите изменение размера, например, CSS переключение класса)
b) Рассчитайте разницу между его начальным и новым размером и вызвать transform с помощью transition
c) Нажмите на него еще раз , пока он меняет свой размер
d) Обратный переход из положения, в котором он находился при нажатии

Моя проблема с шагом d). По какой-то причине элемент резко меняет свой размер не на старый и не на новый, а на совершенно другой размер. У меня есть пример того, что я пытаюсь сделать здесь:

https://codesandbox.io/s/flamboyant-snowflake-47t59

Нажмите на квадрат, а затем нажмите на него еще раз, пока он увеличивается.

Есть ли надежный способ правильно делать то, что я пытаюсь сделать? Есть ли хорошие альтернативы?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2020

Мне удалось найти рабочее решение (оно импортирует библиотеку rematrix, чтобы упростить вычисления с матрицами преобразования). Как это решение, так и более простое решение Ричарда способны к анимации 60 кадров в секунду - я думаю, разница в количестве случаев, с которыми может справиться каждый подход.

https://codesandbox.io/s/working-transform-reverse-urc16

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

Я верю, что это то, что вы ищете. Кроме того, мне кажется, что вы не совсем понимаете requestAnimationFrame полностью. Это сделано, чтобы заменить технику, которая включает рекурсивные вызовы setInterval для изменения свойства CSS элемента каждые несколько миллисекунд (подробнее здесь ). Поэтому я советую сначала прочитать больше о requestAnimationFrame.

Я хотел бы отметить, что эту анимацию ниже можно сделать гораздо проще, просто используя переход CSS. Кроме того, MDN упоминает, что оба они в любом случае имеют более или менее сходную производительность (см. здесь ). Тем не менее, вот минимальный рабочий пример того, что вы хотите:

let clicked = false;
let square = document.querySelector(".small-sq");
let expandID
let retractID

square.style.transformOrigin = 'top left'
square.style.transform = 'scale(1)'
square.addEventListener('click', e => {
  let timeStart = new Date()
  let currentScale = parseFloat(square.style.transform.slice(6, -1))
  if (!clicked) {
    cancelAnimationFrame(retractID)
    expandID = requestAnimationFrame(() => repeat(timeStart, currentScale, clicked))
  }
  else {
    cancelAnimationFrame(expandID)
    retractID = requestAnimationFrame(() => repeat(timeStart, currentScale, clicked))
  }
  clicked = !clicked
})

function repeat(timeStart, currentScale, status) {
    let timeDifference = new Date() - timeStart
    if (status) {
      let scaleValue = currentScale + (1 * timeDifference / 5000) > 2 ? 2 : currentScale + (1 * timeDifference / 5000)
      square.style.transform = `scale(${scaleValue})`
      expandID = requestAnimationFrame(() => repeat(timeStart, scaleValue, status))
      if (scaleValue >= 2)
        cancelAnimationFrame(expandID)
    }
    else {
      let scaleValue = currentScale - (1 * timeDifference / 5000) < 1 ? 1 : currentScale - (1 * timeDifference / 5000)
      square.style.transform = `scale(${scaleValue})`
      retractID = requestAnimationFrame(() => repeat(timeStart, scaleValue, status))
      if (scaleValue <= 1)
        cancelAnimationFrame(retractID)
    }
    
  }
.small-sq {
  height: 100px;
  width: 100px;
  background-color: rgb(131, 42, 131);
}
.big-sq {
  height: 500px;
  width: 500px;
  background-color: rgb(131, 42, 131);
}
<div id="app">
  <div class="small-sq"></div>
</div>

Если вы используете переход CSS, его можно преобразовать в следующее:

let square = document.querySelector('.small-sq')

square.addEventListener('click', e => {
  square.classList.toggle('toggled')
})
.small-sq {
  height: 100px;
  width: 100px;
  background-color: rgb(131, 42, 131);
  transform-origin: left top;
  transition: transform 1s linear;
}
.small-sq.toggled {
  transform: scale(2)
}
<div id="app">
  <div class="small-sq"></div>
</div>
...