如何解决如何使用成帧器运动在React中创建嵌套的递归下拉列表
我想在React中创建一个嵌套的递归下拉列表。我不需要简单的html / css解决方案,因为我的主要目的是使用framer-motion来显示子菜单的动画。我发现很难将第二个子菜单保持打开状态,因为它对相对父级是绝对的,因此当我们将鼠标悬停在子级子菜单上并自动关闭时,父级的onMouseOut将触发。我当时正忙于引用,然后尝试检查子容器的选择器是否包含e.current,但这不起作用。
这是我到目前为止所获得的代码准备的代码沙箱: https://codesandbox.io/s/exciting-worker-9fq2n?file=/src/RecursiveFolder.js。
主要组件:
import React from "react";
import "./styles.css";
import { folders } from "./data";
import RecursiveFolder from "./RecursiveFolder";
import { motion,AnimatePresence } from "framer-motion";
export default function App() {
const [isOpen,setIsOpen] = React.useState(false);
return (
<div className="App">
<div className="wrapper">
<div className="recursive-selector">
<div
onClick={() => {
setIsOpen(!isOpen);
}}
>
<span> Choose folder </span>
</div>
<AnimatePresence>
{isOpen && folders.length && (
<motion.div
className="recursive-selector-collapsed"
initial={{
height: 0,opacity: 0
}}
animate={{
height: "auto",opacity: 1
}}
exit={{
height: 0,opacity: 0
}}
>
{folders
.filter((dir) => !dir.parent_id)
.map((parent) => (
<RecursiveFolder folder={parent} folders={folders} />
))}
</motion.div>
)}
</AnimatePresence>
</div>
</div>
</div>
);
}
递归组件:
import React,{ useState,useRef } from "react";
import { motion,AnimatePresence } from "framer-motion";
import { v4 as uuid } from "uuid";
const RecursiveFolder = (props) => {
const [isUnfolded,setIsUnfolded] = useState(false);
const [key,setKey] = useState("selector-key-init");
const children = props.folders
? props.folders.filter((folder) => folder.parent_id === props.folder.id)
: [];
const selectorRef = useRef(null);
const selectorChildren = useRef(null);
return (
<div
ref={selectorRef}
className={"recursive-selector-parent"}
key={key}
onMouseOver={() => {
setIsUnfolded(true);
}}
onMouseOut={(e) => {
//if (e.current && !e.current.includes(selectorChildren))
setIsUnfolded(false);
setKey(uuid());
}}
>
<div>
<span>{props.folder ? props.folder.name : ""}</span>
</div>
<AnimatePresence>
{isUnfolded && children.length && (
<motion.div
className="recursive-selector-children"
ref={selectorChildren}
initial={{
width: 0,opacity: 0
}}
animate={{
width: "100%",opacity: 1,x: 0
}}
exit={{
width: 0
}}
>
{children.map((el,index) => (
<RecursiveFolder folder={el} folders={props.folders} />
))}
</motion.div>
)}
</AnimatePresence>
</div>
);
};
export default RecursiveFolder;
数据如下:
export const folders = [
{
id: 1,name: "images",parent_id: null
},{
id: 2,name: "files",{
id: 3,name: "videos",{
id: 4,name: "texts",{
id: 5,name: "i1",{
id: 6,name: "i2",{
//children
id: 7,name: "i3",parent_id: 1
},{
id: 8,name: "i4",{
id: 9,{
id: 10,parent_id: 2
},{
id: 11,parent_id: 4
},{
id: 12,parent_id: 5
},{
id: 13,{
id: 14,{
id: 15,parent_id: 6
},{
id: 16,parent_id: 3
},{
id: 17,{
// GRAND CHILDREN
id: 18,parent_id: 7
},{
id: 19,{
id: 20,parent_id: 8
},{
id: 21,{
id: 22,{
id: 23,parent_id: 9
},{
id: 24,{
id: 25,parent_id: 10
}
];
样式
html,body {
margin: 0;
padding: 0;
}
.App {
font-family: sans-serif;
text-align: center;
background: lightgray;
margin: 0;
padding: 0;
height: 100vh;
display: flex;
justify-content: flex-end;
align-items: center;
}
.wrapper {
margin-top: 20px;
}
div.recursive-selector {
width: 100px;
background: #fff;
padding-top: 0.375rem;
padding-bottom: 0.375rem;
padding-right: 1.75rem;
padding-left: 0.75rem;
margin-right: 20px;
border: 1px solid #becad6;
font-weight: 300;
transition: box-shadow 250ms cubic-bezier(0.27,0.01,0.38,1.06),border 250ms cubic-bezier(0.27,1.06);
color: #495057;
background-size: 8px 10px;
cursor: pointer;
position: relative;
border-bottom-left-radius: 0.375rem;
border-bottom-right-radius: 0.375rem;
border-top-left-radius: 0.375rem;
border-top-right-radius: 0.375rem;
}
div.recursive-selector-collapsed {
position: absolute;
left: 0;
top: 100%;
width: 100%;
border: 1px solid #becad6;
font-weight: 300;
color: #495057;
background-size: 8px 10px;
}
div.recursive-selector-parent {
position: relative;
z-index: 2;
background: #fff;
}
div.recursive-selector-parent:hover {
background: lightgray;
}
div.recursive-selector-children {
position: absolute;
top: 0;
right: 100%;
border: 1px solid #becad6;
width: 100%;
}
任何建议都值得赞赏,因为我真的很想解决这个问题。 感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。