React实现VS Code风格文件树:嵌套项转Accordion功能求助
求助:实现VS Code风格侧边栏文件管理器的折叠面板功能
我正在开发类似VS Code侧边栏的文件管理器,已实现顶层文件创建、点击已有文件加号按钮创建嵌套文件的功能。现在需要将嵌套项以**Accordion(折叠面板)**形式呈现,要求:
- 包含子文件的主标题渲染为折叠面板,且支持在其中创建更多嵌套文件
- 子项添加嵌套文件后自动转为折叠面板,无嵌套则显示普通
<p>标签
尝试实现但未成功,附上当前代码及效果截图,恳请帮助。
当前代码
import { Button } from '@/components/ui/button'; import { useEffect, useState } from 'react'; const FileTree = () => { const [files, setFiles] = useState([]); const [editing, setEditing] = useState(null); const [newFileName, setNewFileName] = useState(''); const handleAddFile = (parentIndex = null) => { if (newFileName.trim() === '') return; const newFile = { name: newFileName, children: [] }; if (parentIndex === null) { setFiles([...files, newFile]); } else { const newFiles = [...files]; const addNestedFile = (file, idx) => { if (idx === parentIndex) { file.children.push(newFile); } else { file.children.forEach((child, childIdx) => { addNestedFile(child, `${idx}-${childIdx}`); }); } }; newFiles.forEach((file, idx) => addNestedFile(file, idx.toString())); setFiles(newFiles); } setNewFileName(''); setEditing(null); }; const handleDeleteFile = (index) => { setFiles(files.filter((_, i) => i !== index)); }; const handleDeleteNestedFile = (parentIndex, index) => { const newFiles = [...files]; const deleteNestedFile = (file, idx) => { if (idx === parentIndex) { file.children = file.children.filter((_, i) => i !== index); } else { file.children.forEach((child, childIdx) => { deleteNestedFile(child, `${idx}-${childIdx}`); }); } }; newFiles.forEach((file, idx) => deleteNestedFile(file, idx.toString())); setFiles(newFiles); }; const renderFileTree = (files, parentIndex = null) => { return files.map((file, index) => { const currentIndex = parentIndex === null ? index.toString() : `${parentIndex}-${index}`; console.log(file.children); return ( <div key={currentIndex} style={{ marginLeft: parentIndex !== null ? 20 : 0, borderLeft: parentIndex !== null ? '2px solid #ccc' : 'none', paddingLeft: 10 }}> <div style={{ display: 'flex', alignItems: 'center' }} > <span onMouseEnter={() => setEditing(currentIndex)} className='my-2 border border-white rounded-md px-2 py-1 cursor-pointer hover:border-gray-300 hover:bg-gray-100 hover:text-gray-800' > {file.name} </span> {editing === currentIndex && ( <> <button onClick={() => setEditing(`nested-${currentIndex}`)} style={{ marginLeft: 10 }}>+</button> <button onClick={() => parentIndex === null ? handleDeleteFile(index) : handleDeleteNestedFile(parentIndex, index)} style={{ marginLeft: 10 }}>x</button> </> )} </div> {editing === `nested-${currentIndex}` && ( <div style={{ marginTop: 10 }}> <input value={newFileName} onChange={(e) => setNewFileName(e.target.value)} placeholder="Enter file name" ref={(input) => input && input.focus()} onKeyDown={(e) => { if (e.key === 'Enter') { handleAddFile(currentIndex); } }} /> <button onClick={() => handleAddFile(currentIndex)}>✔</button> <button onClick={() => setEditing(null)}>✖</button> </div> )} {file.children.length > 0 && renderFileTree(file.children, currentIndex)} </div> ); }); }; return ( <div className='pt-56 ml-28'> <div> <Button onClick={() => setEditing('new')}>Create File</Button> </div> {editing === 'new' && ( <div style={{ marginTop: 10 }}> <input value={newFileName} onChange={(e) => setNewFileName(e.target.value)} placeholder="Enter file name" ref={(input) => input && input.focus()} onKeyDown={(e) => { if (e.key === 'Enter') { handleAddFile(); } }} /> <button onClick={() => handleAddFile()}>✔</button> <button onClick={() => setEditing(null)}>✖</button> </div> )} <div style={{ marginTop: 20 }}> {renderFileTree(files)} </div> </div> ); }; export default FileTree;
当前效果

内容的提问来源于stack exchange,提问作者Govind ganeriwal
相关产品推荐
相关产品推荐

