动画是您可以添加到网站的最酷的东西之一,以使其使其流行,并且与其他队列不同。
您可以使用CSS进行大多数动画,但是您必须了解很多才能获得良好的结果。
这就是为什么许多React生态系统中的许多人都喜欢Framer Motion。
它具有清晰,声明和简洁的API,这使得在网络上构建动画是一种乐趣。
使用框架运动的优点
Framer Motion是一个强大的动画库,可以在网页上创建平滑而美丽的动画。以下是使用Framer Motion的一些优点:
- 用户友好的:Framer Motion具有直观的API,即使是针对动画的新手,也可以轻松创建动画。
- 声明性:框架运动使用声明语法,阐明了动画中正在发生的事情。
- 可自定义:Framer Motion提供了广泛的可自定义选项,可帮助您创建适合您特定需求的动画。
- 性能:Framer Motion已针对性能进行了优化,因此您可以创建复杂的动画而不必担心放慢网站。
- 社区:Framer Motion拥有一个庞大而活跃的社区,可提供支持和资源,以帮助您充分利用图书馆。
与Qwik集成
ð§您可以在GitHub上的这篇文章中找到代码。
我以前写过关于how to run React inside Qwik的文章,但在这里是tldr;复习:
- 启动一个新的Qwik应用程序:
pnpm create qwik@latest
- 添加反应集成:
pnpm run qwik add react
然后我们可以添加framer-motion
:
pnpm install framer-motion
现在我们可以用framer-motion
编写一个反应组件。
创建Qwikified的组件
这很简单。可以说我们有此代码:
import { motion } from "framer-motion";
const MyComponent = () => {
return (
<motion.div
animate={{
scale: [1, 2, 2, 1, 1],
rotate: [0, 0, 270, 270, 0],
borderRadius: ['20%', '20%', '50%', '50%', '20%'],
backgroundColor: ['#ff008c', '#d309e1', '#9c1aff', '#7700ff', '#ff008c'],
transition: { duration: 2 },
}}
className="h-52 w-52 rounded bg-green-500"
/>
);
};
我们需要做的一切qwikify是:
// FILE: src/integrations/react/framer.tsx
// ==========================================
// 👇🏽 this tells Qwik that the JSX here is React
/** @jsxImportSource react */
import { motion } from "framer-motion";
// one function to import
import { qwikify$ } from '@builder.io/qwik-react';
const MyComponent = () => (
<motion.div
animate={{
scale: [1, 2, 2, 1, 1],
rotate: [0, 0, 270, 270, 0],
borderRadius: ['20%', '20%', '50%', '50%', '20%'],
backgroundColor: ['#ff008c', '#d309e1', '#9c1aff', '#7700ff', '#ff008c'],
transition: { duration: 2 },
}}
className="h-52 w-52 rounded bg-green-500"
/>
);
// All you need is to export:
export const FramerQwik = qwikify$(MyComponent);
在我们的好老朋友Github Copilot的帮助下,让我们分解:
- 从
@builder.io/qwik-react
导入qwikify$
函数。 - 从
framer-motion
导入motion
组件。 - 创建一个返回
div
元素的MyComponent
功能组件。 - 将
animate
prop传递给motion.div
元素。 - 将对象作为包含动画属性的动画道具的值。
- 将
className
prop传递给motion.div
元素。 - 使用
qwikify$
函数导出组件。
然后我们可以在Qwik应用中使用它:
// FILE: src/routes/index.tsx
// ==========================================
import { component$ } from '@builder.io/qwik';
import { FramerQwik } from '~/integrations/react/framer';
export default component$(() => {
return (
<div class="flex flex-col gap-4">
<h1 class="text-3xl">Qwik/React Framer Motion</h1>
<div class="grid place-content-center">
<FramerQwik client:idle />
</div>
</div>
);
});
注意,在上面的示例中,我们使用client:idle
,这是何时补充反应组件的指令。这告诉Qwik等待浏览器idle
事件,然后水合物反应,导致Qwik海洋中的一个反应岛。
更复杂的东西怎么样?
Qwik内部的React Framer Mover图像库
让我们以framer-motion
文档的示例并将其转换为qwik组件。
我喜欢这个小图片库:
让我们创建一个新文件:src/integrations/react/image-gallery.tsx
。
我们将所有内容都放在一个文件中
/** @jsxImportSource react */
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { wrap } from 'popmotion';
import { qwikify$ } from '@builder.io/qwik-react';
const images = [
'https://d33wubrfki0l68.cloudfront.net/dd23708ebc4053551bb33e18b7174e73b6e1710b/dea24/static/images/wallpapers/shared-colors@2x.png',
'https://d33wubrfki0l68.cloudfront.net/49de349d12db851952c5556f3c637ca772745316/cfc56/static/images/wallpapers/bridge-02@2x.png',
'https://d33wubrfki0l68.cloudfront.net/594de66469079c21fc54c14db0591305a1198dd6/3f4b1/static/images/wallpapers/bridge-01@2x.png',
];
const variants = {
enter: (direction: number) => {
return {
x: direction > 0 ? 1000 : -1000,
opacity: 0,
};
},
center: {
zIndex: 1,
x: 0,
opacity: 1,
},
exit: (direction: number) => {
return {
zIndex: 0,
x: direction < 0 ? 1000 : -1000,
opacity: 0,
};
},
};
const swipeConfidenceThreshold = 10000;
const swipePower = (offset: number, velocity: number) => {
return Math.abs(offset) * velocity;
};
export const Example = () => {
const [[page, direction], setPage] = useState([0, 0]);
const imageIndex = wrap(0, images.length, page);
const paginate = (newDirection: number) => {
setPage([page + newDirection, newDirection]);
};
return (
<div className='framer-gallery'>
<AnimatePresence initial={false} custom={direction}>
<motion.img
key={page}
src={images[imageIndex]}
custom={direction}
variants={variants}
initial="enter"
animate="center"
exit="exit"
transition={{
x: { type: 'spring', stiffness: 300, damping: 30 },
opacity: { duration: 0.2 },
}}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
dragElastic={1}
onDragEnd={(e, { offset, velocity }) => {
const swipe = swipePower(offset.x, velocity.x);
if (swipe < -swipeConfidenceThreshold) {
paginate(1);
} else if (swipe > swipeConfidenceThreshold) {
paginate(-1);
}
}}
/>
</AnimatePresence>
<div className="next" onClick={() => paginate(1)}>
{'‣'}
</div>
<div className="prev" onClick={() => paginate(-1)}>
{'‣'}
</div>
</div>
);
};
export const ImageGallery = qwikify$(Example);
在这一点上,我们要做的就是导入src/routes/index.tsx
中的组件并决定如何加载它:
// FILE: src/routes/index.tsx
// ==========================================
import { component$ } from '@builder.io/qwik';
import { FramerQwik } from '~/integrations/react/framer';
import { ImageGallery } from '~/integrations/react/image-gallery';
export default component$(() => {
return (
<div class="flex flex-col gap-4">
<h1 class="text-3xl">Qwik/React Framer Motion</h1>
<div class="grid place-content-center">
<FramerQwik client:idle />
</div>
<ImageGallery client:visible />
</div>
);
});
要注意的一件事是与原始代码和原始框的微小区别在于,我将片段(<>
)更改为
使用className
只是为了使样式更容易。否则,在组件的情况下,我们添加了client:visible
加载策略,才能在视图中看到画廊时进行水合。
这就是它的样子:
一切都起作用!
这里最酷的部分之一(至少对书呆子með)是画廊的代码仅在视图时执行。
检查一下(注意网络选项卡):
奖金:运动'替代framer-motion
使用framer-motion
很酷,但它具有进口反应和水合的成本。
如果我告诉您有一个动画库,它的性能与制定者一样,重量较小,并且具有非常相似的API?
另外,它是由构建framer-motion
(和Pose和Popmotion)的同一个人创建的。
我在谈论Motion One。
这不是React库,而是用于性能的香草JS动画库,其捆绑面积非常低为3.8kb。
运动一个人具有与框架相同的铃铛和哨子,与固体和vue的集成以及dedicated devtools。
需要我说更多?
Qwik运动一个例子
尽管这没有Qwik SDK,但让我们看看如何添加基本动画。
由于此库是纯JS,因此我们可以使用Qwik方法useVisibleTask()
,仅在浏览器中运行此代码,如下示例:
import { component$, useVisibleTask$ } from '@builder.io/qwik';
import { animate } from 'motion';
export default component$(() => {
useVisibleTask$(() => {
animate(
'#animation-target',
{
scale: [1, 2, 2, 1, 1],
rotate: [0, 0, 270, 270, 0],
borderRadius: ['20%', '20%', '50%', '50%', '20%'],
backgroundColor: [
'#ff008c',
'#d309e1',
'#9c1aff',
'#7700ff',
'#ff008c',
],
},
{
duration: 2,
easing: 'ease-in-out',
repeat: 2,
direction: 'alternate',
}
);
});
return (
<div
id="animation-target"
// Some tailwind styling for sizing and initial color
class="m-auto mt-24 w-52 h-52 bg-slate-500"
></div>
);
});
我们对动画使用了相同的值,与framer-motion
示例中。但是,我们将值作为对象传递。
还注意到,animate
函数的第三个参数是选项所在的位置,与framer
不同的是,那里的transition
键在animate
Prop中传递。
结论
在这篇文章中,我展示了我们如何在qwik应用程序中同时使用framer-motion
和Motion One
。
在我看来,使用强大的动画库是一个巨大的胜利。
如果您已经使用framer-motion
,那么仅添加您可能已经在React应用程序中构建的相同动画就几乎没有摩擦。
拥有此选项可能有助于在性能和美丽运动设计的情况下逐步采用Qwik。
视觉上与您的组件构建
Builder.io是一个视觉CMS,可让您使用your components在网站上创建内容。