最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Framer Motion exit animation not firing on accordion with react-router-dom - Stack Overflow

programmeradmin9浏览0评论

So I've got this accordion-layout working with react-router-dom using a rather unconventional markup structure.

Demo: =/src/Case.js

Shortened code for one accordion header:

      <motion.div
        layout
        transition={transition}
        key={item.id}
        style={{
          flex: isActive ? 1 : 0,
          flexBasis: isActive ? null : 56,
          ...
        }}
      >
        <NavLink
          style={{
            ...
          }}
          exact={true}
          to={item.url}
        />

        <Route exact path={item.url}>
          <motion.div
            transition={{ delay: 1, ...transition }}
            variants={{
              open: { opacity: 1 },
              collapsed: { opacity: 0 }
            }}
            initial="collapsed"
            animate="open"
            exit="collapsed"
            layout
            style={{
              ...
            }}
          >
            <Home />
          </motion.div>
        </Route>
      </motion.div>

And I'm trying to get framer-motion to animate between the accordion pages. Like in the gif below

You can see that it works fine to animate the in transition. But struggles to animate the exit prop on page change. Clicking on an accordion header, the content is abruptly hidden. Looks like it is being removed from the DOM without any consideration to AnimateSharedLayout or AnimatePresence. I tried adding in exitBeforeEnter props but it doesn’t work.

Any ideas?

So I've got this accordion-layout working with react-router-dom using a rather unconventional markup structure.

Demo: https://codesandbox.io/s/falling-violet-kvqn2?file=/src/Case.js

Shortened code for one accordion header:

      <motion.div
        layout
        transition={transition}
        key={item.id}
        style={{
          flex: isActive ? 1 : 0,
          flexBasis: isActive ? null : 56,
          ...
        }}
      >
        <NavLink
          style={{
            ...
          }}
          exact={true}
          to={item.url}
        />

        <Route exact path={item.url}>
          <motion.div
            transition={{ delay: 1, ...transition }}
            variants={{
              open: { opacity: 1 },
              collapsed: { opacity: 0 }
            }}
            initial="collapsed"
            animate="open"
            exit="collapsed"
            layout
            style={{
              ...
            }}
          >
            <Home />
          </motion.div>
        </Route>
      </motion.div>

And I'm trying to get framer-motion to animate between the accordion pages. Like in the gif below

You can see that it works fine to animate the in transition. But struggles to animate the exit prop on page change. Clicking on an accordion header, the content is abruptly hidden. Looks like it is being removed from the DOM without any consideration to AnimateSharedLayout or AnimatePresence. I tried adding in exitBeforeEnter props but it doesn’t work.

Any ideas?

Share Improve this question asked Aug 12, 2020 at 9:38 umbrielumbriel 7511 gold badge7 silver badges25 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 14 +100

You will need to make some changes in your code:

  1. Work with variants -> you can orchestration animations start: By default, all these animations will start simultaneously. But by using variants, we gain access to extra transition props like when, delayChildren, and staggerChildren that can let parents orchestrate the execution of child animations.

  2. Also, looks like you will need to work with width to change div sizes. I tried to do with flexBasis but i really couldnt do it, the transition just doesnt work.

  3. Remove <Route> as a "wrapper" of motion.div. It also stops the motion to do the animations/transitions.

  4. Add <AnimatePresence> as a wrapper of motion.div children. You can check more here

So, my code looks like this:

I create this 2 variants:

const divVariants = {
  expanded: {
    width: "55%",
   transition: {
      duration: 1.2,
      ease: [0.83, 0, 0.17, 1]
    }
  },
  collapsed: {
    width: "15%",
    transition: {
      duration: 1.2,
      ease: [0.83, 0, 0.17, 1]
    }
  }
};

const tagVariants = {
  show: {
    opacity: 1,
    transition: {
      delay: 1,
      duration: 1.2,
      ease: [0.83, 0, 0.17, 1]
    }
  },
  hidden: {
    opacity: 0,
    transition: {
      duration: 1.2,
      ease: [0.83, 0, 0.17, 1]
    }
  }
};

motion.div :

<!-- Parent -->
<motion.div
        layout
        variants={divVariants}
        animate={isActive ? "expanded" : "collapsed"}
        initial={false}
        data-section={item.id}
        key={item.id}
        style={{
          overflow: "hidden",
          zIndex: i,
          display: "flex",
          position: "relative",
          backgroundColor: `hsl(${i * 20},100%,50%)`
        }}
      >

<!-- Children -->
<AnimatePresence>
          {isActive && (
            <motion.div
              layout
              variants={tagVariants}
              initial="hidden"
              animate="show"
              exit="hidden"
              style={{
                padding: 20,
                maxWidth: "100%",
                maxHeight: "100%",
                width: "100%",
                height: "100%",
                overflowY: "hidden",
                overflowX: "hidden"
              }}
            >
              <Tag data={data} />
            </motion.div>
          )}
        </AnimatePresence>

I also added some inline styles to all Cases:

<div
      <!-- Avoid div to wrap when it is collapsing -->
      style={{
        whiteSpace: "nowrap",
        overflow: "hidden"
      }}
    >
      home 0
    </div>

And finally

You can check the code here!

发布评论

评论列表(0)

  1. 暂无评论