likes
comments
collection
share

Framer Motion第二弹,动画效果的创意实现!Framer Motion第二弹,动画效果的创意实现! 上一章节刚

作者站长头像
站长
· 阅读数 23

上一章节刚介绍了Framer Motion,这不昨天无意间看到了一个网站的动画效果,今天使用Framer Motion来实现一下。

效果地址:steam-portfolio-demo.vercel.app/

效果分析

Framer Motion第二弹,动画效果的创意实现!Framer Motion第二弹,动画效果的创意实现! 上一章节刚

动画并不复杂,但是应用到网站中使得网站看起来比较有活力,整体效果很好。

这个效果包含两个动画:

  • 动画一:内容从底部弹出,并且伴随着透明度的改变
  • 动画二:遮罩层从左向右退出

我们直接使用Framer Motion来实现这个效果,如果对该库不了解的可以阅读上一篇文章。

效果实现

这个效果是应用到网站的内容上面,会多处使用,所以使用组件实现;这里要使用组合动画variants以及两个钩子函数useAnimation、useInView

  • useAnimation:返回一个控制动画的对象,可以使用它来手动触发、停止或修改动画。对于需要在事件(如点击、悬停)中动态控制动画的场景特别有用。
  • useInView:用于检测一个组件是否在视口中。通常用于触发滚动进入视图时的动画。

我们先来实现上面提到的动画一:

//改变透明度和纵向的位置
const variantsMain = {
  hidden: { opacity: 0, y: 75 },
  visible: { opacity: 1, y: 0 },
};

//动画组件
<div ref={ref} style={{ position: "relative", width, overflow: "hidden", ...style }}>
    <motion.div
      variants={variantsMain}
      initial="hidden"
      animate={mainControls}
      transition={{ duration: 0.5, delay: 0.25 }}
    >
        {/* 网站内容 */}
        {children} 
    </motion.div>
</div>

animate属性由visible字符串设置为控制动画的对象mainControls,通过元素是否出现在视口来执行相应的动画:

const ref = useRef(null);
const isInView = useInView(ref);
const mainControls = useAnimation();

useEffect(() => {
    if (isInView) {
        mainControls.start("visible");
    } else {
        mainControls.start("hidden");
    }
}, [isInView]);

这样动画一就完成了,动画二实现思路和一相同,我直接把动画组件MotionView的代码贴在下面:

import React, { memo, useEffect, useRef } from "react";

import { motion, useAnimation, useInView } from "framer-motion";
import { useThemeToken } from "@/theme/hooks";

interface Props {
  children: React.ReactNode;
  width?: "fit-content" | "100%";
  style?: React.CSSProperties;
}

const variantsMain = {
  hidden: { opacity: 0, y: 75 },
  visible: { opacity: 1, y: 0 },
};
const variantsSlide = {
  hidden: { left: 0 },
  visible: { left: "100%" },
};
const MotionView = memo(({ width = "fit-content", children, style = {} }: Props) => {
  const ref = useRef(null);

  const isInView = useInView(ref);
  const mainControls = useAnimation();
  const slideControls = useAnimation();
  const { colorPrimary } = useThemeToken();

  useEffect(() => {
    if (isInView) {
      mainControls.start("visible");
      slideControls.start("visible");
    } else {
      mainControls.start("hidden");
      slideControls.start("hidden");
    }
  }, [isInView]);
  return (
    <div ref={ref} style={{ position: "relative", width, overflow: "hidden", ...style }}>
      <motion.div
        variants={variantsMain}
        initial="hidden"
        animate={mainControls}
        transition={{ duration: 0.5, delay: 0.25 }}
      >
        {children}
      </motion.div>
      <motion.div
        variants={variantsSlide}
        initial="hidden"
        animate={slideControls}
        transition={{ duration: 0.5, ease: "easeIn" }}
        style={{
          position: "absolute",
          top: 4,
          bottom: 0,
          left: 0,
          right: 0,
          background: colorPrimary,
          zIndex: 10,
        }}
      />
    </div>
  );
});

export default MotionView;

使用动画到网站内容:

<MotionView>
    <div>Hey, I'm LEOPAI.</div>
</MotionView>

<MotionView>
  <div>
    I'm a <span style={{ color: colorPrimary }}>Front-end Developer, React Developer</span>
  </div>
</MotionView>

我随便画了案例网站中的一些元素来实现整体效果,录制了一段视频来展示一下:

无法上传,请移步公众号观看。

我加入了主题色,可以改变主题色来改变动画的颜色。我这里设置的是元素离开视口就退出动画回到初始状态,和案例网站中不同,如果想像案例的网站一样只执行一次,可以使用once选项:

const isInView = useInView(ref, { once: true });

介绍完毕,感谢您的阅读!

转载自:https://juejin.cn/post/7401066742069690380
评论
请登录