reactjs 帧运动:如何设置SVG的视框大小的动画?

kiayqfof  于 2023-06-05  发布在  React
关注(0)|答案(1)|浏览(154)

我有一个标志的SVG,当滚动时,从全名切换到只有首字母。它位于一个容器div中,有一个彩色背景,也应该相应地改变大小。到目前为止,我已经能够将额外的字符动画化,并将首字母移动到正确的空间,但我在如何更新/动画化容器div的大小方面遇到了问题。
我有它目前的工作使用GSAP,但我们切换到成帧运动。这有点难以解释,所以这里是当前的工作版本:https://pixelbakery.com/about(我希望允许链接)
注意:我们使用Tailwind作为我们的样式框架。
我现在的代码:
1.你可以忽略这一部分-这是我如何计算滚动位置。我添加它只是为了以防你想要一些 prop 的额外上下文:

const [isHamActive, setHamToggle] = useState(false)
  const [windowHeight, setwindowHeight] = useState(0)
  const [showNavBar, setShowNavBar] = useState(true)
  const [scrollPosition, setScrollPosition] = useState(0)

  function handleShowNavBar() {
    if (scrollPosition + 1 >= windowHeight / 3) setShowNavBar(false)
    else setShowNavBar(true)
  }
  // Create a window resize event listener
  useEffect(() => {
    setwindowHeight(window.innerHeight)
    const handleWindowResize = () => {
      setwindowHeight(window.innerHeight)
      handleShowNavBar()
    }
    window.addEventListener('resize', handleWindowResize)
    return () => {
      window.removeEventListener('resize', handleWindowResize)
      handleShowNavBar()
    }
  }, [])

  // Create a scroll event listener, and call handleShowNavBar
  useEffect(() => {
    setScrollPosition(window.scrollY + 1)
    handleShowNavBar()
    const handleScroll = () => {
      const position = window.scrollY + 1
      setScrollPosition(position)
      handleShowNavBar()
    }
    window.addEventListener('scroll', handleScroll, { passive: true })

    return () => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [scrollPosition])

1.父组件/完整导航栏

import { motion, Variants } from 'framer-motion'
import Nav_Logo from './Nav_Logo'
export default function Navbar() {
  const navItem: Variants = {
    offscreen: (delay) => ({
      y: -300,
      transition: {
        ease: 'easeOut',
        duration: 1,
        delay: delay,
      },
    }),
    onscreen: (delay) => ({
      y: 0,
      transition: {
        ease: 'easeOut',
        duration: 1,
        delay: delay,
      },
    }),
  }

 return (
    <>
      <motion.div initial='offscreen' className={'z-40 '}>
        <motion.div
          initial={'offscreen'}
          animate={'onscreen'}
          variants={navItem}
          custom={0.3}
          className='navItem origin-top-left ml-8 mt-8 fixed top-0 left-0 z-40 '
        >
          <div className='bg-cream rounded-md origin-top-left hidden xl:block  '>
            <Link
              hrefLang={'en-US'}
              href={'/'}
              className=' pointer-events-auto block relative min-w-full z-40 px-4 pt-3 my-0 w-full'
            >
              <Nav_Logo showNavBar={showNavBar} />
            </Link>
          </div>
        </motion.div>
      </motion.div>
    </>
  )
}

1.下面是SVG徽标组件

import { Variants, motion } from "framer-motion";

const fadeAway: Variants = {
  hide: (delay) => ({
    opacity: 0,
    transition: {
      ease: "easeOut",
      duration: 1,
      delay: delay,
    },
  }),
  show: (delay) => ({
    opacity: 1,
    transition: {
      ease: "easeOut",
      duration: 1,
      delay: delay,
    },
  }),
};

const Nav_Logo = ({ showNavBar }) => {
  return (
    <motion.svg
      xmlns='http://www.w3.org/2000/svg'
      version='1.1'
      id='Logo_Wordmark'
      viewBox='0 0 494 138'
      width={"100%"}
      preserveAspectRatio='xMaxYMin meet'
    >
      {/* P */}
      <motion.path d='...' />
      {/* IXEL */}
      <motion.g
        variants={fadeAway}
        animate={showNavBar ? "show" : "hide"}
      >  ... </motion.g>
      {/* B */}
      <motion.path
        animate={showNavBar ? {{x: 0}} : {{x: -140}}
        d='...'
      />
      {/* AKERY */}
      <motion.g
        variants={fadeAway}
        animate={showNavBar ? "show" : "hide"} 
      >
       ...
      </motion.g>
      {/* D */}
      <motion.path
        animate={showNavBar ? {{scale: 1}} : {{scale: 1.4, y:-10}}
        ...
      />
      {/* ESIGN */}
      <motion.g
        variants={fadeAway}
        animate={showNavBar ? "show" : "hide"}
      >
        ...
      </motion.g>
      {/* S */}
      <motion.path
        animate={showNavBar ? {{scale: 1}} : {{scale: 1.4, y:-10}}}
        p='...'
      />
      {/* TUDIO */}
      <motion.g
        variants={fadeAway}
        animate={showNavBar ? "show" : "hide"}
      >
        ...
      </motion.g>
    </motion.svg>
  )
}

export default Nav_Logo;

改变视框大小是最好的方法吗?

2uluyalo

2uluyalo1#

我不知道这是否有用,但它很有趣。你不能对SVG的viewBox进行动画处理,但是如果你删除了它,CSS中的所有值都将引用上下文文档。这里我切换SVG上的样式small

document.forms.f1.addEventListener('submit', e => {
  e.preventDefault();
  document.querySelector('svg').classList.toggle('small');
});
svg {
  display: block;
  width: 20em;
  height: 7em;
  transition: all 1s;
}

svg text {
  dominant-baseline: middle;
  text-anchor: middle;
  font-size: 200%;
  font-family: sans-serif;
  font-weight: bold;
  fill: #ff5e64;
  transition: font-size .1s .3s;
}

svg text:nth-child(even) {
  font-size: 270%;
}

tspan {
  transition: fill-opacity .3s, font-size .1s .3s;
}

.small {
  width: 6em;
}

.small .tail {
  fill-opacity: 0;
  font-size: 0;
}

.small text:nth-child(odd) {
  font-size: 270%;
}
<svg>
  <rect width="100%" height="100%" rx="5%" fill="#efe8f2" />
  <text x="50%" y="40%">
    <tspan class="head">p</tspan><tspan class="tail">ixel&nbsp;</tspan><tspan class="head">b</tspan><tspan class="tail">akery</tspan>
  </text>
  <text x="50%" y="70%" >
    <tspan class="head">d</tspan><tspan class="tail">esign&nbsp;</tspan><tspan class="head">s</tspan><tspan class="tail">tudio</tspan>
  </text>
</svg>

<form name="f1">
  <button>toggle</button>
</form>

相关问题