【react实现递归编辑树】
2023-12-26 18:51:27
import React, {useState} from 'react';
import {Input} from 'antd';
import {
DeleteOutlined,
PlusCircleOutlined,
CaretDownOutlined,
} from '@ant-design/icons';
function findAndUpdateObjectById(id, arr, changeObj, type = '') {
console.log('arguments', arguments)
function findAndModify(currentArray) {
for (let i = 0; i < currentArray.length; i++) {
const currentItem = currentArray[i];
if (currentItem.id === id) {
const updatedItem = {...currentItem, ...changeObj};
if (type === 'subtract') {
return [
...currentArray.slice(0, i),
...currentArray.slice(i + 1)
];
}
if (changeObj.children && changeObj.children.length > 0) {
return [
...currentArray.slice(0, i),
{...currentItem, children: [...currentItem.children, ...changeObj.children]},
...currentArray.slice(i + 1)
];
}
return [
...currentArray.slice(0, i),
updatedItem,
...currentArray.slice(i + 1)
];
}
if (currentItem.children && currentItem.children.length > 0) {
const result = findAndModify(currentItem.children);
if (result) {
const updatedArray = [...currentArray];
updatedArray[i] = {...currentItem, children: result};
return updatedArray;
}
}
}
return null;
}
return findAndModify(arr);
}
function Menu() {
const [menuItems, setMenuItems] = useState([]);
const [activeId, setActiveId] = useState(null);
const handleAddMenuItem = (_, currentId: '') => {
const newId = Date.now();
const newMenuItem = {
id: newId,
editing: true,
text: '菜单项' + newId,
collapsed: true,
children: [],
};
if (!!currentId) {
setActiveId(newId);
setMenuItems(prevItems => findAndUpdateObjectById(currentId, prevItems, {children: [newMenuItem]}))
return;
}
setActiveId(newId);
setMenuItems(prevItems => [...prevItems, newMenuItem]);
};
const handleDeleteMenuItem = (id) => {
setMenuItems((prevItems) => findAndUpdateObjectById(id, prevItems, {}, 'subtract'))
};
const handleToggleEdit = (id) => {
setMenuItems((prevItems) => findAndUpdateObjectById(id, prevItems, {editing: false}))
};
const handleChangeText = (id, newText) => {
setMenuItems((prevItems) => findAndUpdateObjectById(id, prevItems, {text: newText}))
};
const handleMenuItemClick = (id) => {
setMenuItems((prevItems) => findAndUpdateObjectById(id, prevItems, {editing: true}))
setActiveId(id);
}
;
const handleMenuItemCollapsed = (e, item) => {
const collapsed = item.collapsed;
setMenuItems((prevItems) => findAndUpdateObjectById(item.id, prevItems, {collapsed: !collapsed}))
setActiveId(item.id);
}
return (
<div style={{width: '500px', height: '600px', backgroundColor: '#fff'}}>
<button onClick={handleAddMenuItem}>新增</button>
{menuItems.map(item => (
<MenuItem
key={item.id}
item={item}
onDelete={handleDeleteMenuItem}
onToggleEdit={handleToggleEdit}
onChangeText={handleChangeText}
onClick={handleMenuItemClick}
onAddChild={handleAddMenuItem}
onCollapsed={handleMenuItemCollapsed}
activeId={activeId}
/>
))}
</div>
);
}
function MenuItem({item, onAddChild, onDelete, onToggleEdit, onChangeText, onClick, activeId, onCollapsed}) {
const handleDoubleClick = () => {
onToggleEdit(item.id);
};
const handleChange = (e) => {
e.stopPropagation(); // 阻止事件冒泡
onChangeText(item.id, e.target.value);
};
const handleDelete = (e) => {
e.stopPropagation(); // 阻止事件冒泡
onDelete(item.id);
};
const handleClick = (e) => {
e.stopPropagation(); // 阻止事件冒泡
onClick(item.id);
};
const handleAdd = (e) => {
e.stopPropagation(); // 阻止事件冒泡
onAddChild(e, item.id)
}
const handleCollapsed = (e, item) => {
e?.stopPropagation && e?.stopPropagation(); // 阻止事件冒泡
onCollapsed(e, item)
}
return (
<div>
<div style={{display: 'flex'}}>
{item.children.length > 0 && (
<div
style={{display: 'inline'}}
onClick={(e) => handleCollapsed(e, item)}>
<CaretDownOutlined rotate={item.collapsed ? 0 : -90}/>
</div>)}
{item.id === activeId && item.editing ? (
<div style={{width: '480px'}}>
<Input type="text" value={item.text} onChange={handleChange} onBlur={handleDoubleClick} autoFocus/>
</div>
) : (
<div style={{
width: '500px',
padding: '5px',
backgroundColor: item.id === activeId ? 'rgb(218, 235, 254)' : '#fff',
display: 'flex',
justifyContent: 'space-between'
}}
onClick={handleClick}
onDoubleClick={handleDoubleClick}>
<span>{item.text}</span>
<div style={{width: 40, display: 'flex', justifyContent: 'space-between'}}>
<PlusCircleOutlined onClick={handleAdd}/>
<DeleteOutlined onClick={handleDelete}/>
</div>
</div>
)
}
</div>
<div style={{marginLeft: item.children.length ? 20 : 0}}>
{item.collapsed &&
item.children.map((childItem) => (
<MenuItem
key={childItem.id}
item={childItem}
onDelete={onDelete}
onToggleEdit={onToggleEdit}
onChangeText={onChangeText}
onClick={onClick}
onAddChild={onAddChild}
activeId={activeId}
onCollapsed={handleCollapsed}
/>
))}
</div>
</div>
);
}
export default Menu;
文章来源:https://blog.csdn.net/m0_56542349/article/details/135227610
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!