页面转换取决于路线(Next.js 14 和 Framer Motion)

问题描述 投票:0回答:1

在我的应用程序中,我实现了一个选项卡式导航栏,以方便在不同类别的地点之间导航,每个地点都有自己的路线。我已使用嵌套布局文件中的以下代码成功地在这些路线之间应用了页面转换。

Screen Recording

但是,我遇到了两个具体问题:

  1. 过渡动画和模态:当用户单击某个项目时, 在以下命令的帮助下导航到以模态形式呈现的不同路线 并行路线。我在页面转换方面面临挑战 当模态打开或关闭时,动画仍在模态后面运行。 虽然我已经设法部分阻止了这种情况,但仍然存在一些问题 发生重叠。

  2. 基于选项卡位置的转换方向:此外,我想要 过渡方向由选项卡在中的位置确定 导航栏。例如,如果用户单击右侧的选项卡 对于当前动画,我希望动画从左移至 对吧。

我尝试利用 useParams() 挂钩来获取当前路由。然后,对于每次更改,我的目标是使用 useRef() 存储以前的版本。如果前一个路径和当前路径都不包含 place 属性,我打算增加另一个计数器 keyCounter,用 useRef(0) 初始化,它用作运动元素的键。然而,尽管我尝试了,我还是无法让它按预期工作。

const FrozenRouter = (props: PropsWithChildren<{}>) => {
  const context = useContext(LayoutRouterContext);
  const frozen = useRef(context).current;
  return <LayoutRouterContext.Provider value={frozen}>{props.children}</LayoutRouterContext.Provider>;
};

const Layout = ({ children }: { children: ReactNode }) => {
  const params = useParams();
  const paramsBeforeChange = useRef<Params>({});
  const keyCounter = useRef(0);

  useEffect(() => {
    const { city: cityBeforeChange, category: categoryBeforeChange, place: placeBeforeChange } = paramsBeforeChange.current;
    const { city: cityAfterChange, category: categoryAfterChange, place: placeAfterChange } = params;

    if (placeBeforeChange !== undefined || placeAfterChange !== undefined) {
      console.log("shouldn't animate");
      return;
    }

    keyCounter.current++;
    paramsBeforeChange.current = params;
  }, [params]);

  return (
    <>
      <Navbar />
      <AnimatePresence mode="popLayout" initial={false}>
        <motion.main
          key={keyCounter.current}
          className="h-screen overflow-y-scroll pb-8 pt-28"
          initial={{ opacity: 1, x: "-100%" }}
          animate={{ opacity: 1, x: 0 }}
          exit={{ opacity: 1, x: "100%" }}
          transition={{ duration: 0.6, ease: "easeInOut" }}
        >
          <FrozenRouter>{children}</FrozenRouter>
        </motion.main>
      </AnimatePresence>
    </>
  );
};
reactjs next.js next.js13 framer-motion app-route
1个回答
0
投票

在 React 中处理过渡动画和模态有时会很棘手,特别是在处理嵌套路由和它们之间的过渡时。让我们分解您的两个问题,看看如何解决它们:

过渡动画和模态

为了防止在模态框打开或关闭时过渡动画在模态框后面运行,您可以根据模态框的存在有条件地应用动画。以下是如何调整代码的示例:

import { useState } from 'react';

const Layout = ({ children }: { children: React.ReactNode }) => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  // Function to handle opening and closing of the modal
  const handleModalToggle = () => {
    setIsModalOpen(!isModalOpen);
  };

  return (
    <>
      <Navbar />
      <AnimatePresence>
        {/* Conditionally apply animation based on modal state */}
        {isModalOpen ? (
          <ModalComponent onClose={handleModalToggle} />
        ) : (
          <motion.main
            className="h-screen overflow-y-scroll pb-8 pt-28"
            initial={{ opacity: 0, x: '-100%' }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: '100%' }}
            transition={{ duration: 0.6, ease: 'easeInOut' }}
          >
            {children}
          </motion.main>
        )}
      </AnimatePresence>
    </>
  );
};

export default Layout;

在此代码中:

  • 我们使用
    isModalOpen
    状态来跟踪模态框是打开还是关闭。
  • 根据
    isModalOpen
    状态,我们有条件地渲染模态组件或具有所需动画的主要内容。
  • ModalComponent
    是实际模态组件的占位符,
    handleModalToggle
    是切换模态状态的函数。

基于选项卡位置的过渡方向

要根据选项卡在导航栏中的位置确定过渡方向,您可以考虑使用自定义挂钩或上下文来管理导航状态。这是一个简化的示例:

import { useState } from 'react';

// Custom hook to manage navigation state
const useNavigation = () => {
  const [selectedTab, setSelectedTab] = useState<string>('');

  const handleTabChange = (tab: string) => {
    // Determine transition direction based on tab position
    // For example, you can compare tab indices or names
    // and set a transition direction accordingly

    setSelectedTab(tab);
  };

  return { selectedTab, handleTabChange };
};

const Layout = ({ children }: { children: React.ReactNode }) => {
  const { selectedTab, handleTabChange } = useNavigation();

  return (
    <>
      <Navbar onTabChange={handleTabChange} />
      <AnimatePresence>
        {/* Conditionally apply animation based on selected tab */}
        {selectedTab === 'SomeTabName' ? (
          <motion.main
            className="h-screen overflow-y-scroll pb-8 pt-28"
            initial={{ opacity: 0, x: '-100%' }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: '100%' }}
            transition={{ duration: 0.6, ease: 'easeInOut' }}
          >
            {children}
          </motion.main>
        ) : (
          <OtherComponent />
        )}
      </AnimatePresence>
    </>
  );
};

export default Layout;

在此代码中:

  • 我们使用
    useNavigation
    自定义挂钩来管理所选选项卡状态并处理选项卡更改。
  • 根据所选选项卡,我们有条件地应用不同的动画或渲染不同的组件。
  • 您可以根据您的具体需求自定义
    handleTabChange
    功能来确定过渡方向。
© www.soinside.com 2019 - 2024. All rights reserved.