首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在React中修复我的Framer Motion动画?

如何在React中修复我的Framer Motion动画?
EN

Stack Overflow用户
提问于 2020-02-04 00:35:40
回答 1查看 2.6K关注 0票数 1

我一直在尝试重新创建一个类似于TypeForm用于创建问题的UI。

如果你在他们的编辑器中注意到,当你使用箭头时,右边的滚动就像一个页面的上下滚动。

对于我的应用程序,我希望它以相同的方式滚动,但只需单击左侧的问题即可

它几乎可以工作,但是当第一次按相反的顺序点击一个问题时,动画中有一个小错误-它重叠-这就是问题所在。我正在试着让上上下下的问题不会相互重叠,你能帮我吗?

目前,它的工作方式是根据您是否选择了“上一个”问题来更改动画的initialanimateexit

这是一个指向codesandbox的链接,因为我无法让下面的代码片段正确运行...

代码语言:javascript
复制
import React, { useState, useEffect, useRef } from "react";

import { motion, AnimatePresence } from "framer-motion"
import uuid from 'uuid/v4';
import './styles.css';

const App = () => {
  const [display, setDisplay] = useState(false);
  const [questions, setQuestions] = useState([{id:uuid(), q: '', active:true}]);
  const [isPrevious, setIsPrevious] = useState(false);
  const [prev, setPrev] = useState(0);
  const toggleMenu = () => setDisplay(!display);
  const selectType = ()=> {
    setDisplay(false);
    setPrev(questions.findIndex(x=>x.active === true))
    setQuestions(prevState => {
      let updated = prevState.map(question=>{
        question.active = false;
        return question
      })
      updated.push({id:uuid(), q: '', active:true})
      return updated
    })
  }
  useEffect(()=>{
    setPrev(questions.findIndex(x=>x.active === true))
  },[questions])
  const updateQuestions = ({id, q}) => setQuestions(prevState => prevState.map((question, index) => {
    question.active = false;
    if(question.id === id) {
      console.log({'prev': prev, 'current': index, 'isPrev?': isPrevious})
      if(prev > index) {
        setIsPrevious(true)
      } else {
        setIsPrevious(false)
      }
      question.q = q
      question.active = true
    } 
    return question
  }))
  const removeQuestion = (id) => setQuestions(prevState => prevState.filter(question => question.id !== id))
  return (
    <> 
      <Navbar />
      <main className="flex items-stretch justify-between">
        <div className="w-1/2">
          {questions.map(question=>
            <Qshort key={question.id} removeQuestion={removeQuestion} data={question} updateQuestion={updateQuestions}/>
          )}
          <div className="relative mt-10 px-4">
            <button onClick={toggleMenu} className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Add your first question</button>
            <div className={(display ? "flex " : "hidden ") + "absolute bg-white p-3 flex-col shadow-md w-1/2 rounded-lg"}>
              <button onClick={() => selectType("1")} className="my-3 mt-0 p-3 hover:bg-gray-200 rounded">Short question</button>             
            </div>
          </div>
        </div>
        <div className="rightSide relative w-1/2 bg-gray-200 flex flex-col items-center justify-center">
          <AnimatePresence finishBeforeExit>
          {questions.length &&
              <motion.div
              transition={{ duration: 1, type: "tween" }}
                key={questions[questions.findIndex(x=>x.active)].id}
                
                initial={{opacity:0, bottom:isPrevious ? '100%' : '-50%'}} 
                animate={{opacity:1, bottom:'50%'}} 
                exit={{opacity:0, bottom:isPrevious ? '-20%' : '100%'}} 
                className="absolute flex flex-col w-64 w-2/3"
              >
              <p className="text-2xl pl-3 text-gray-600">{questions[questions.findIndex(x=>x.active)].q}</p>
              <input 
                placeholder="Type your answer here...." 
                type="text" 
                className="mt-3 w-full p-3 bg-transparent border-b-4 text-2xl"
              />
            </motion.div>
          }
          </AnimatePresence>
          {questions.length && 
            <button className="absolute mb-3 mr-3 bottom-0 right-0 bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-6 rounded">Next step</button>
          }
        </div>
      </main>
    </>
  );
};


const Qshort = ({updateQuestion,removeQuestion,data}) => {
  return (
    <div className={(data.active ? 'border-green-500 ':'border-transparent')+" border relative bg-gray-300 py-8 pb-12 pl-4 mb-2"}>
      <input 
        onFocus={(e)=>updateQuestion({id:data.id, q:e.target.value})} 
        onChange={(e)=>updateQuestion({id:data.id, q:e.target.value})} 
        type="text" 
        className="w-full bg-transparent" 
        placeholder="Type your question here..."
      />
      <button onClick={()=>removeQuestion(data.id)} className="absolute bottom-0 right-0 mr-3 mb-3 text-xs text-blue-500 hover:text-blue-700">Remove</button>
    </div> 
  );
};

const Navbar = () => {
  return (
    <nav className="relative flex items-center justify-between flex-wrap bg-blue-500 p-6">
      <div className="flex items-center flex-shrink-0 text-white mr-6">
        <span className="font-semibold text-xl tracking-tight">Aquire</span>
      </div>
      <div className="block lg:hidden">
        <button className="flex items-center px-3 py-2 border rounded text-teal-200 border-teal-400 hover:text-white hover:border-white">
          <svg
            className="fill-current h-3 w-3"
            viewBox="0 0 20 20"
            xmlns="http://www.w3.org/2000/svg"
          >
            <title>Menu</title>
            <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" />
          </svg>
        </button>
      </div>
    </nav>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/uuid.v4@1.0.0/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/framer-motion@0.6.6/dist/framer-motion.js"></script>

  <div id="root"></div>

EN

回答 1

Stack Overflow用户

发布于 2020-02-04 23:53:01

我以前从来没有用过框架运动。这是非常有趣的,有点酷。但我认为一旦设置了元素出口属性,就不能再更新了。这个问题可能会在以后的版本中得到解决。

我将你的问题重构为react-spring。我对它更熟悉,我认为它更成熟。它正在与这个库一起工作。我不知道在这个项目中,更改库是否是你的一个选择。

您可以这样定义过渡:

代码语言:javascript
复制
const transitions = useTransition(
  questions.filter(x => x.active),
  item => item.id,
  {
    from: { opacity: 0, bottom: isPrevious.current ? "100%" : "-50%" },
    enter: { opacity: 1, bottom: "50%" },
    leave: { opacity: 0, bottom: isPrevious.current ? "-20%" : "100%" }
  }
);

这就是你使用它的方式。

代码语言:javascript
复制
{questions.length &&
  transitions.map(({ item, props, key }) => (
    <animated.div
      className="absolute flex flex-col w-64 w-2/3"
      key={key}
      style={props}
    >
      <p className="text-2xl pl-3 text-gray-600">{item.q}</p>
      <input
        placeholder="Type your answer here...."
        type="text"
        className="mt-3 w-full p-3 bg-transparent border-b-4 text-2xl"
      />
    </animated.div>
  ))
}

我必须将isPrevious更改为ref,以便与其他状态同步。

代码语言:javascript
复制
const isPrevious = useRef(false);

https://codesandbox.io/s/condescending-montalcini-dywpu

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60043450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档