前言
相信很多前端同學都或多或少和影片打過交道,有的時候是產品想要的過度效果;有的時候是UI想要的酷炫影片,但是有沒有人考慮過,是不是我們的頁面上面的每一次變化,都可以像是自然而然的變化;是不是每一次用戶點擊所產生的互動,都可以在頁面上活過來呢?
歡迎你打開了新的前端影片世界——《Framer Motion》
效果體驗
這里,我在framer官網上面給大家錄制了一下大概的使用效果,
在我們的常規認知中,實作這樣的效果其實需要很多的css來實作,或者說需要我們進行大量的定制化邏輯撰寫,但是如果我們使用framer motion的話,只需要如下代碼:
import { AnimatePresence, motion } from 'framer-motion';
const [selectedId, setSelectedId] = useState(null);
{items.map(item => (
<motion.div layoutId={item.id} onClick={() => setSelectedId(item.id)}>
<motion.h5>{item.subtitle}</motion.h5>
<motion.h2>{item.title}</motion.h2>
</motion.div>
))}
<AnimatePresence>
{selectedId && (
<motion.div layoutId={selectedId}>
<motion.h5>{item.subtitle}</motion.h5>
<motion.h2>{item.title}</motion.h2>
<motion.button onClick={() => setSelectedId(null)} />
</motion.div>
)}
</AnimatePresence>
從上面的實作我們可以看出,framer-motion可以說是我們在用react動效開發程序中的必備利器,那么接下來,我給大家簡單介紹一些framer motion的基礎用法,
快速開始
Framer Motion 需要 React 18 或更高版本,
安裝
從npm安裝framer-motion
npm install framer-motion
輸入
安裝后,您可以通過framer-motion引入Framer Motion
import { motion } from "framer-motion"
export const MyComponent = ({ isVisible }) => (
<motion.div animate={{ opacity: isVisible ? 1 : 0 }} />
)
使用方式
Framer motion的核心API是motion的組件,每個HTML和SVG標簽都有對應的motion組件,
他們渲染的結果與對應的原生組件完全一致,并在其之上增加了一些影片和手勢相關的props,
比如:
<motion.div />
<motion.span />
<motion.h1 />
<motion.svg />
...
示例
比如我們現在想要實作一個側邊欄效果,
節點的掛載與卸載(mount、unmount)
如果我們自己來實作的話,可能要考慮它的keyframe,它的初始狀態與最終的css樣式,那么如果用framer-motion來如何實作呢?
首先我們來設計一個會動的按鈕Icon:
import * as React from "react";
import { motion } from "framer-motion";
const Path = props => (
<motion.path
fill="transparent"
stroke
stroke="hsl(0, 0%, 18%)"
strokeLinecap="round"
{...props}
/>
);
const MenuToggle = ({ toggle }) => (
<button onClick={toggle}>
<svg height="23" viewBox="0 0 23 23">
<Path
variants={{
closed: { d: "M 2 2.5 L 20 2.5" },
open: { d: "M 3 16.5 L 17 2.5" }
}}
/>
<Path
d="M 2 9.423 L 20 9.423"
variants={{
closed: { opacity: 1 },
open: { opacity: 0 }
}}
transition={{ duration: 0.1 }}
/>
<Path
variants={{
closed: { d: "M 2 16.346 L 20 16.346" },
open: { d: "M 3 2.5 L 17 16.346" }
}}
/>
</svg>
</button>
);
接下來,就由這個按鈕來控制側邊欄的展示(mount)與隱藏(unmount):
import * as React from "react";
import { useRef } from "react";
import { motion, useCycle } from "framer-motion";
import { useDimensions } from "./use-dimensions";
const sidebar = {
open: (height = 1000) => ({
clipPath: `circle(${height * 2 + 200}px at 40px 40px)`,
transition: {
type: "spring",
stiffness: 20,
restDelta: 2
}
}),
closed: {
clipPath: "circle(30px at 40px 40px)",
transition: {
delay: 0.5,
type: "spring",
stiffness: 400,
damping: 40
}
}
};
export const Example = () => {
const [isOpen, toggleOpen] = useCycle(false, true);
const containerRef = useRef(null);
const { height } = useDimensions(containerRef);
return (
<motion.nav
initial={false}
animate={isOpen ? "open" : "closed"}
custom={height}
ref={containerRef}
>
<motion.div className="background" variants={sidebar} />
<MenuToggle toggle={() => toggleOpen()} />
</motion.nav>
);
};
也就是說,其實我們更多需要做的事情,從思考如何設計各元素之間的css聯動與keyframe書寫變成了如何按照檔案寫好framer-motion的配置,哪個更輕松相信大家一目了然,
串列
側邊欄一般都是帶有選單的,那么我們是不是可以讓這個側邊欄也有一個逐次出現的效果呢?就像這樣:
這里我們是不是已經開始肌肉記憶般的計算延遲時間,思考如何進行整體效果的分配,那么如果這里我們使用frame motion,它的實作方式應該是怎么樣的呢?
首先我們先來進行單個Item的封裝:
import * as React from "react";
import { motion } from "framer-motion";
const variants = {
open: {
y: 0,
opacity: 1,
transition: {
y: { stiffness: 1000, velocity: -100 }
}
},
closed: {
y: 50,
opacity: 0,
transition: {
y: { stiffness: 1000 }
}
}
};
const colors = ["#FF008C", "#D309E1", "#9C1AFF", "#7700FF", "#4400FF"];
export const MenuItem = ({ i }) => {
const style = { border: `2px solid ${colors[i]}` };
return (
<motion.li
variants={variants}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
<div className="icon-placeholder" style={style} />
<div className="text-placeholder" style={style} />
</motion.li>
);
};
然后我們在已封裝Item的基礎上,再進行整個選單的封裝:
import * as React from "react";
import { motion } from "framer-motion";
const itemIds = [0, 1, 2, 3, 4];
const variants = {
open: {
transition: { staggerChildren: 0.07, delayChildren: 0.2 }
},
closed: {
transition: { staggerChildren: 0.05, staggerDirection: -1 }
}
};
export const Navigation = () => (
<motion.ul variants={variants}>
{itemIds.map(i => (
<MenuItem i={i} key={i} />
))}
</motion.ul>
);
沒錯,影片!就是這么簡單!
更多API
更詳細、更具體的功能大家可以參考下官方的使用檔案,我就不在這里一一列舉了,
美中不足
其實不難看出,不論是實作的效果,還是使用方式,對于前端的同學來說framer-motion都是非常友好的工具,這一點從npm的Weekly Downloads以及github的star上面都不難看出,
但是目前也有一個問題,那就是包的體積問題,
這個包的大小對于部分的系統來說,還是不夠友好,這也是很多人不選擇使用它的原因,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/522967.html
標籤:其他
