Framer:检查元素是否进入视口
Framer: Check if element is into viewport
在我的网站上使用 Framer Motion API 创建交互和动画时,我找不到如何使用它来在屏幕上显示某些内容时触发动画。
例如,此 SVG 绘制正确,但 Framer 不等待元素出现在视口上并在加载站点后立即触发它:
import React, { Component } from 'react'
import { motion } from "framer-motion";
class IsometricScreen extends Component {
constructor() {
super()
this.icon = {
hidden: { pathLength: 0 },
visible: { pathLength: 1 }
}
}
render() {
return (
<motion.svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 1000" className="svg-mobile">
<motion.path
d="M418,988.93H82c-39.76,0-72-32.24-72-72V83.07c0-39.76,32.24-72,72-72h336c39.76,0,72,32.24,72,72v833.86
C490,956.69,457.76,988.93,418,988.93z"
variants={this.icon}
initial="hidden"
animate="visible"
transition={{
default: { duration: 2, ease: "easeInOut" }
}}
/>
</motion.svg>
)
}
}
export default IsometricScreen
Framer 是否有视口检测触发器可以在这里实现?
我终于用一个微小的功能组件解决了这个问题:
function inViewport() {
const isInViewport = el => {
const rect = el.getBoundingClientRect()
const vertInView = (rect.top <= window.innerHeight) && ((rect.top + rect.height) >= 0)
const horInView = (rect.left <= window.innerWidth) && ((rect.left + rect.width) >= 0)
return (vertInView && horInView)
}
this.elms = document.querySelectorAll('.showOnScreen')
window.addEventListener("scroll", () => {
this.elms.forEach(elm => isInViewport(elm) ? elm.classList.add('visible') : elm.classList.remove('visible'))
})
}
export default inViewport
或者,您可以使用 Intersection Observer,与 React 和 framer motion 很好地融合。
import { useInView } from "react-intersection-observer"; // 1.9K gzipped
import { motion, useAnimation } from "framer-motion";
const Component = () => {
const animation = useAnimation();
const [ref, inView, entry] = useInView({ threshold: 0.1 });
useEffect(() => {
if (inView) {
animation.start("visible");
} else {
animation.start("hidden");
}
}, [animation, inView]);
const variants = {
visible: {
y: 0,
opacity: 1,
transition: { duration: 0.5, delayChilden: 0.2, staggerChildren: 0.1 },
},
hidden: {
y: enter,
opacity: 0,
},
}
return (
<motion.div
ref={ref}
animate={animation}
initial="hidden"
variants={{variants}}
/>
);
}
您还可以通过查看入口对象(从顶部或底部进入等)来优化动画
framer-motion
自版本 5.3 起内置了对此用例的支持。
这是一个演示模式的 CodeSandbox:https://codesandbox.io/s/framer-motion-animate-in-view-5-3-94j13
相关代码:
function FadeInWhenVisible({ children }) {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
transition={{ duration: 0.3 }}
variants={{
visible: { opacity: 1, scale: 1 },
hidden: { opacity: 0, scale: 0 }
}}
>
{children}
</motion.div>
);
}
用法:
<FadeInWhenVisible>
<Box />
</FadeInWhenVisible>
在我的网站上使用 Framer Motion API 创建交互和动画时,我找不到如何使用它来在屏幕上显示某些内容时触发动画。
例如,此 SVG 绘制正确,但 Framer 不等待元素出现在视口上并在加载站点后立即触发它:
import React, { Component } from 'react'
import { motion } from "framer-motion";
class IsometricScreen extends Component {
constructor() {
super()
this.icon = {
hidden: { pathLength: 0 },
visible: { pathLength: 1 }
}
}
render() {
return (
<motion.svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 1000" className="svg-mobile">
<motion.path
d="M418,988.93H82c-39.76,0-72-32.24-72-72V83.07c0-39.76,32.24-72,72-72h336c39.76,0,72,32.24,72,72v833.86
C490,956.69,457.76,988.93,418,988.93z"
variants={this.icon}
initial="hidden"
animate="visible"
transition={{
default: { duration: 2, ease: "easeInOut" }
}}
/>
</motion.svg>
)
}
}
export default IsometricScreen
Framer 是否有视口检测触发器可以在这里实现?
我终于用一个微小的功能组件解决了这个问题:
function inViewport() {
const isInViewport = el => {
const rect = el.getBoundingClientRect()
const vertInView = (rect.top <= window.innerHeight) && ((rect.top + rect.height) >= 0)
const horInView = (rect.left <= window.innerWidth) && ((rect.left + rect.width) >= 0)
return (vertInView && horInView)
}
this.elms = document.querySelectorAll('.showOnScreen')
window.addEventListener("scroll", () => {
this.elms.forEach(elm => isInViewport(elm) ? elm.classList.add('visible') : elm.classList.remove('visible'))
})
}
export default inViewport
或者,您可以使用 Intersection Observer,与 React 和 framer motion 很好地融合。
import { useInView } from "react-intersection-observer"; // 1.9K gzipped
import { motion, useAnimation } from "framer-motion";
const Component = () => {
const animation = useAnimation();
const [ref, inView, entry] = useInView({ threshold: 0.1 });
useEffect(() => {
if (inView) {
animation.start("visible");
} else {
animation.start("hidden");
}
}, [animation, inView]);
const variants = {
visible: {
y: 0,
opacity: 1,
transition: { duration: 0.5, delayChilden: 0.2, staggerChildren: 0.1 },
},
hidden: {
y: enter,
opacity: 0,
},
}
return (
<motion.div
ref={ref}
animate={animation}
initial="hidden"
variants={{variants}}
/>
);
}
您还可以通过查看入口对象(从顶部或底部进入等)来优化动画
framer-motion
自版本 5.3 起内置了对此用例的支持。
这是一个演示模式的 CodeSandbox:https://codesandbox.io/s/framer-motion-animate-in-view-5-3-94j13
相关代码:
function FadeInWhenVisible({ children }) {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
transition={{ duration: 0.3 }}
variants={{
visible: { opacity: 1, scale: 1 },
hidden: { opacity: 0, scale: 0 }
}}
>
{children}
</motion.div>
);
}
用法:
<FadeInWhenVisible>
<Box />
</FadeInWhenVisible>