FLIP технология фронтенд-анимации

JavaScript

предисловие

Обычно большинство веб-приложений, которые мы используем, просто переключаются с одного представления на другое, что приводит к неинтуитивному взаимодействию с пользователем, но мы можем сделать это интерактивное поведение более приличным с помощью технических средств:

При создании пользовательского интерфейса добавьте разумные эффекты перехода пользовательского интерфейса, чтобы избежать прыжков и телепортации. Если вы примените какие-то естественные движения в жизни к анимации пользовательского интерфейса, это вызовет яркие эмоции у ваших пользователей. В конце концов, все, с чем вы взаимодействуете, проистекает из естественного движения жизни.

Далее мы рассмотрим класс значимых анимаций пользовательского интерфейса, улучшающих взаимодействие с пользователем, с которыми вы, возможно, знакомы. У этой техники есть технический термин, а именно FLIP (первый, последний, инвертированный, воспроизведенный). Технология FLIP может динамически изменять положение и размер элементов DOM с высокой производительностью, независимо от того, как рассчитывается или визуализируется их макет (например, высота, ширина, плавающая точка, абсолютное позиционирование, Flexbox, сетка и т. д.). В процессе изменения будет дан определенный динамический эффект, чтобы достичь нужной нам цели, сделать динамический эффект пользовательского интерфейса более разумным и соответственно улучшить работу пользователя.

переход между представлениями

При переходе из одного представления в другое в мобильном приложении элемент, находящийся в фокусе, часто перемещается из одной позиции в другую между представлениями. Например, следующие сценарии:

Эффекты расширения и сжатия изображения

Если вы хотите сделать анимацию более плавной, постарайтесь сделать количество вычислений стиля как можно меньше и как можно быстрее. Ключ в том, чтобы использовать в анимации только трансформацию и непрозрачность. Просто использовать преобразование и непрозрачность просто разочаровывает. Но, к счастью, FLIP позволяет нам имитировать изменения макета, используя только преобразование.

Что такое ФЛИП

FLIP — это запоминающее устройство и технология, впервые предложенная Полом Льюисом. FLIP — это аббревиатура от четырех слов First, Last, Invert и Play. Вот краткое заявление:

Во-первых, прежде чем что-либо произойдет (до перехода), запишите положение и размер текущего элемента. Вы можете использовать API getBoundingClientRect() для обработки, например:

const first = el.getBoundingClientRect()

Этот код используется для получения границ элемента getBoundingClientRect() вернет объект DOMRect, как показано ниже:

Последнее: выполнение фрагмента кода, соответствующее изменение элемента и запись положения и размера элемента в последнем состоянии, например:

// 通过给元素添加一个类名,设置元素最后状态的位置和大小 
//(在.totes-at-the-end中添加相应的样式规则),布局发生了变化
el.classList.add('totes-at-the-end') 
// 记录元素最后状态的位置和尺寸大小 
const last = el.getBoundingClientRect()

Инвертировать: рассчитать изменение положения между первой позицией (первой) и последней позицией (последней) элемента (и изменение размера между двумя состояниями, если необходимо), а затем использовать эти числа для выполнения определенных вычислений, позволяя элементу двигаться (путем преобразования положения и размера элемента), создавая иллюзию того, что он находится в первой позиции (начальной позиции):

const deltaX = first.left - last.left const deltaY = first.top - last.top 
const deltaW = first.width / last.width const deltaH = first.height / last.height

Воспроизведение: чтобы инвертировать элемент (представить, что он находится в первой позиции), мы можем установить для преобразования значение none, переместить его в последнюю позицию и анимировать элемент:

elm.animate([ { transformOrigin: 'top left', transform: ` translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH}) ` }, { transformOrigin: 'top left', transform: 'none' }], { duration: 300, easing: 'ease-in-out', fill: 'both' } );

Примечание. В Play используется API веб-анимации. Если вы никогда не касались соответствующего API,нажмите сюда, чтобы узнать больше

Соедините весь код следующим образом:

// 获取当前元素的边界 
const first = el.getBoundingClientRect() 
// 通过给元素添加一个类名,设置元素最后状态的位置和大小 (在.totes-at-the-end中添加相应的样式规则) // 布局发生了变化 
el.classList.add('totes-at-the-end') // 记录元素最后状态的位置和尺寸大小 
const last = el.getBoundingClientRect() 
const deltaX = first.left - last.left const deltaY = first.top - last.top 
const deltaW = first.width / last.width const deltaH = first.height / last.height elm.animate([ { transformOrigin: 'top left', transform: ` translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH}) ` }, { transformOrigin: 'top left', transform: 'none' }], { duration: 300, easing: 'ease-in-out', fill: 'both' } );

Чтобы всем было проще понять принцип динамического эффекта, создаваемого технологией FLIP, для демонстрации используется следующая картинка, которая может быть проще для понимания:

Эффект анимации, достигнутый с помощью последнего процесса Play, показан на следующем рисунке:

Специальное заявление об отказе от ответственности: два изображения выше предоставлены @davidkpiano на CSS Dev Conf 2017.«FLIP сообщает об анимированных макетах»в теме

Переходы для общих элементов

В приложениях переход представлений и переход элементов в разные состояния является очень распространенным эффектом.Самый основной принцип заключается в том, что начальное состояние элемента отличается от конечного состояния. В Android это похоже на переходы между общими элементами, за исключением того, что элементы не «перерабатываются» из одного представления в другое в DOM, как в Android.

Далее, давайте посмотрим на эффект перехода FLIP:

Кратко объясните процесс расчета:

// 首先获取点被点击图片的位置和尺寸 
let firstRect = itemImage.getBoundingClientRect(); 
// 然后获取详情的位置和尺寸 
let lastRect = detailItem.getBoundingClientRect(); // 详情到图片的动效 

detailItem.animate( [ { transform: ` translateX(${firstRect.left - lastRect.left}px) translateY(${firstRect.top - lastRect.top}px) scale(${firstRect.width / lastRect.width}) ` }, { transform: ` translateX(0) translateY(0) scale(1) ` } ], { duration: 600, easing: 'cubic-bezier(0.2, 0, 0.2, 1)' } ); 
// 详情的位置和尺寸 
let itemImageRect = itemImage.getBoundingClientRect(); 
// 原图片的位置和尺寸 
let detailItemRect = detailItem.getBoundingClientRect(); 
// 详情回到图片的动效 
itemImage.animate( [ { zIndex: 2, transform: ` translateX(${detailItemRect.left - itemImageRect.left}px) translateY(${detailItemRect.top - itemImageRect.top}px) scale(${detailItemRect.width / itemImageRect.width}) ` }, { zIndex: 2, transform: ` translateX(0) translateY(0) scale(1) ` } ], { duration: 600, easing: 'cubic-bezier(0.2, 0, 0.2, 1)' } );

Суммировать

Я надеюсь, что эта статья будет полезна для вашего производства анимации!