Как создать длительность в ванильном JavaScript?

#javascript #animation

#javascript #Анимация

Вопрос:

Сегодня я спрашиваю себя, как создать параметр длительности, подобный GreenSock, с его функциями.

Чтобы было понятно, как создать анимирующую функцию, которая занимает длительность в чистом ванильном JavaScript?

Они делают это, добавляя длительность перехода с помощью JavaScript? 🙂 Я хотел бы получить решение в простом JS.

У меня есть несколько идей, может быть, ширина :

 new Date()
  

Или некоторые :

 setInterval()
  

Например, как обрабатывать длительность здесь?

HTML :

 <div class="box"></div>
  

CSS

 .box {
  width: 200px;
  height: 200px;
  background: orange;
}
  

JavaScript

 const box =   document.querySelector('.box');
function move(duration){
  box.style.transform =  "translateX(50px)";
}
move(2000)
  

Спасибо, если кто-то проходит мимо, чтобы помочь мне! 🙂

Комментарии:

1. Используйте WebAPI для установки transition-property: transform и transition-duration: 2000ms ?

2. Ну, я ищу решение без перехода CSS-продолжительность, если это возможно, я это уже знаю. Использует ли Greensock CSS transition-duration под капотом?

Ответ №1:

 const box = document.querySelector('.box')

function move(duration){
  box.style['transition-property'] = 'transform'
  box.style['transition-duration'] = `${duration}ms`
  setTimeout(() => box.style.transform =  "translate3d(200px,0,0)")
}

move(2000)  
 .box {
  width: 200px;
  height: 200px;
  background: orange;
}  
 <div class="box"></div>  

Если вы не хотите использовать CSS для управления переходом, вам придется управлять им вручную, используя requestAnimationFrame и вашу собственную функцию смягчения:

 const EASE_IN_OUT = (t) => 
  t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2)   1

const ease = (f, easing = EASE_IN_OUT) => (...args) => easing(f(...args))

const limit = (f, limit = 1) => (...args) => 
  { const result = f(...args); return result > limit ? limit : result }

const elapsedFraction = ({ start, duration }) => 
  (performance.now() - start) / duration

const asInteger = (f) => (...args) => f(...args).toFixed(0)

const calcX = asInteger(({ start, duration, distance }) => 
  ease(limit(elapsedFraction))({ start, duration }) * distance)

function move({ el, duration, distance }) {
  const start = performance.now()
  const startX = el.getBoundingClientRect().x

  const tick = () => {
    if (el.getBoundingClientRect().x - startX === distance) return
    el.style.transform = `translate3d(${calcX({ start, duration, distance })}px,0,0)`
    requestAnimationFrame(tick)
  }

  tick()
}

const el = document.querySelector(".box")
move({ el, duration: 1000, distance: 200 })  
 .box {
  width: 200px;
  height: 200px;
  background: orange;
}  
 <div class="box"></div>  

Комментарии:

1. Это хорошо, но есть ли решение без CSS transition-duration ? Использует ли GSAP CSS-переход под капотом?

2. Это действительно приятно, хотя и немного сложно для понимания, вот почему я проверил другой вариант. Но ваше решение тоже действительно хорошее, плюс оно добавляет облегчения, и это здорово.

Ответ №2:

Я думаю, что лучший способ — использовать библиотеку анимации. Но я сделал пример, используя «translate3d». Translate3d работает на графическом процессоре, а не в процессоре, из-за этого он более производителен. Я также привел пример чистого CSS.

 const box =   document.querySelector('.box');
const blue = document.querySelector('.blue');

function move(elem, duration){
  let posx = elem.getBoundingClientRect().x
  let counter = duration
  
  const timer = setInterval(() => {
     if (counter <= 0) {
      clearInterval(timer)
     }
     
     posx  = 2
     elem.style.transform = `translate3d(${posx}px,0,0)`
     counter -= 10
  }, 10)
}

move(box, 2000)

setTimeout(() => blue.classList.add('act'), 1000)  
 .box {
  width: 60px;
  height: 60px;
  background: orange;
}

.blue {
  width: 60px;
  height: 60px;
  transform: translate3d(0,0,0);
  background: lightblue;
  transition: all 0.8s ease;
}

.act {
  transform: translate3d(100px,0,0)
}  
 <div class="box"></div>
<br>
<div class="blue"></div>  

Комментарии:

1. На самом деле это хорошее решение, спасибо вам за это!

2. Вы должны использовать requestAnimationFrame , а не setInterval при анимации элементов.

3. Вы правильно @BenAston!! Я должен был использовать requestAnimatioFrame вместо этого. Гораздо более производительный!! Спасибо за предложение!

Ответ №3:

Я думаю, что эта функция делает то, что вы хотите:

 Element.prototype.move = function(duration, distance) {
  this.style.transition = duration   's';
  this.style.transform =  'translateX('   distance   'px)';;
};  
 .box {
  width: 200px;
  height: 200px;
  background: orange;
}  
 <div class="box" onclick="this.move(2, 400);">Click me!</div>  

Комментарии:

1. Анимация margin — плохая идея с точки зрения производительности, и я ищу способ без CSS transition-duration. Спасибо за это, хотя! 🙂