先看一下效果:整体的效果
新增效果 --默认值是 default
修改效果 -
大致效果如上
---------------------------------------------------------------------------------------------------------------------------------
下面讲解代码如何实现的
根据你使用的UI的框架中的树结构---形成相应的数据结构(递归形式)-如果后端给你分好了(感谢他)
这个是给我的是一个 数组包裹的对象形式 进行递归
这个我写在--一个通用的 js 导出形式 这边我需要是的是两种类型 所以分了一下(效果图上的是第一个)
解释一下:data:后端给你的数据
parentId是 从0 或者 -1 开始 看你的需求 我这边是 -1show:我这是区分我要的是那种类型
递归形式走的
export function buildTree(data, parentId, show) {
const result = [];
data?.filter(item => item.parentId === parentId)
.forEach(items => {
const children = buildTree(data, items.id, show);
let node = ''
if (!show) {
node = {
value: `${items.categoryName}`,
key: `${items.id}`,
defaultValue: `${items.categoryName}`,
isEditable: false,
parentId: `${items.parentId}`,
children: children.length ? children : undefined,
};
} else {
node = {
value: `${items.id}`,
title: `${items.categoryName}`,
children: children.length ? children : undefined,
};
}
result.push(node);
});
return result;
}
这边都是实现的代码了-------可以详细看下 ---谢谢 -如果不懂-请评论
import { DownOutlined, EditOutlined, PlusOutlined, MinusOutlined, CloseOutlined, CheckOutlined } from '@ant-design/icons';
import { Input, Tree, message } from 'antd';
import React, { useEffect, useState } from 'react';
import moment from 'moment';
import { GetclubGoodsCategoryList, PostclubGoodsCategoryRemove, PostclubGoodsCategorySave, PostclubGoodsCategoryUpdate } from '@/services/commodity';
import { buildTree } from '@/utils/utils';
const { TreeNode } = Tree;
// 三张图
import reduce from '@/assets/icon/reduce.png';
import addIng from '@/assets/icon/addIng.png';
import editIng from '@/assets/icon/editIng.png';
function TreeData({ onNodeClick }) {
// 佛祖保佑,不会报错
const [selectedNode, setSelectedNode] = useState(null);
// const treeData = buildTree(data1, 0);
const expandedKeyArr = ["0"];
const [data, setData] = useState();
const [listObj, setListObj] = useState({});
let isMounted = true;
const getDate = async () => {
try {
//获取最初的数据 ------------接口
let res = await GetclubGoodsCategoryList();
if (isMounted && res && res.code == "200") {
const treeData = buildTree(res.data, 0);
setData(treeData);
}
} catch (error) {
console.error("Error fetching data: ", error);
}
};
useEffect(() => {
getDate();
return () => {
isMounted = false;
};
}, []);
const [expandedKeys, setExpandedKeys] = useState(expandedKeyArr);
// 修改---树结构 有值---接口
const onChangeUpdate = async () => {
if (Object.keys(listObj).length > 0) {
let res = await PostclubGoodsCategoryUpdate({
categoryName: listObj.value,
// parentId: listObj.key,
id: listObj.key,
});
if (res && res.code == "200") {
message.success("修改成功");
//重新获取树形结构
getDate();
}
}
}
const onExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys);
};
const handleNodeClick = (node) => {
setSelectedNode(node);
// 进行暴露---作为一个组件调用你所点击的值对象
onNodeClick(node);
};
const renderTreeNodes = (data, depth = 0) => {
return data?.map((item) => {
const title = item.isEditable ? (
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}>
{/* 输入框显示 和 一个对号 一个 叉号
*/}
<Input placeholder="输入名称" defaultValue={item.defaultValue}
onChange={(e) => onChange(e, item)} />
<CheckOutlined style={{
margin: '0 4px',
}} onClick={() => onSave(item)} />
<CloseOutlined onClick={() => onClose(item.parentKey, item.defaultValue)} />
</div>
) : (
<div onClick={() => handleNodeClick(item)}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div
style={{
whiteSpace: 'nowrap'
}}
>{item.value}</div>
<div
style={{
display: 'flex',
flexWrap: 'nowrap',
alignItems: 'center',
}}
>
{/* <EditOutlined onClick={() => onEdit(item.key)} />
<PlusOutlined onClick={() => onAdd(item.key)} />
{item.parentKey !== "0" && (
<MinusOutlined onClick={() => onDelete(item.key)} />
)} */}
{/* 两层之上就没有图标l
效果上的左边字 右边图片
*/}
{
item.value &&
<>
<img style={{ margin: '0 4px' }} width='15px' onClick={() => onEdit(item.key)} height='15px' src={editIng} alt="" />
{
depth < 2 && <img width='15px' onClick={() => onAdd(item.key)} height='15px' src={addIng} alt="" />
}
<img style={{ margin: '0 4px' }} onClick={() => onDelete(item.key)} width='15px' height='15px' src={reduce} alt="" />
</>
}
</div>
</div>
);
if (item.children) {
return (
<TreeNode title={title} key={item.key}>
{renderTreeNodes(item.children, depth + 1)}
</TreeNode>
);
}
return <TreeNode title={title} key={item.key} />;
});
};
const onAdd = (key) => {
if (expandedKeys.indexOf(key) === -1) {
expandedKeys.push(key);
}
setExpandedKeys(expandedKeys.slice());
addNode(key, data);
setData([...data]);
};
const onEdit = (key) => {
editNode(key, data);
setData([...data]);
};
const editNode = (key, data) =>
data.forEach((item) => {
if (item.key === key) {
item.isEditable = true;
} else {
item.isEditable = false;
}
item.value = item.defaultValue;
if (item.children) {
editNode(key, item.children);
}
});
const getRandomNumber = (min = 1, max = 10000) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
const addNode = (key, data) =>
data.forEach((item) => {
if (item.key === key) {
if (item.children) {
item.children.push({
value: "default",
key: getRandomNumber(),
parentKey: key,
isEditable: false,
showAdd: true
});
} else {
item.children = [
{
value: "default",
key: getRandomNumber(),
parentKey: key,
isEditable: false,
showAdd: true
},
];
}
return;
}
if (item.children) {
addNode(key, item.children);
}
});
const onChange = (e, key) => {
changeNode(key.parentKey ? key : key, e.target.value, data);
setData([...data]);
};
const changeNode = (key, value, data) =>
data.forEach((item) => {
if (item.parentKey || item.key == key.key) {
item.value = value;
}
if (item.children) {
changeNode(key, value, item.children);
}
});
// 保存---数据新增---接口
const onSaveObj = async () => {
let res = await PostclubGoodsCategorySave({
categoryName: listObj.value,
parentId: listObj.parentKey,
})
if (res && res.code === 200) {
message.success('新增成功')
getDate();
} else {
message.error('新增失败')
}
};
useEffect(() => {
if (listObj.showAdd) {
onSaveObj();
} else {
onChangeUpdate()
}
}, [listObj])
const onSave = (key) => {
if (key.value == undefined) {
message.error('请输入分类名称')
return
}
setListObj(key)
saveNode(key, data);
setData([...data]);
};
const saveNode = (key, data) =>
data.forEach((item) => {
if (item.parentKey === key) {
item.defaultValue = item.value;
}
if (item.children) {
saveNode(key, item.children);
}
item.isEditable = false;
});
const onClose = (key, defaultValue) => {
closeNode(key, defaultValue, data);
setData([...data]);
};
const closeNode = (key, defaultValue, data) =>
data.forEach((item, index) => {
item.isEditable = false;
if (item.parentKey === key) {
data.splice(index, 1);
item.value = defaultValue;
}
if (item.children) {
closeNode(key, defaultValue, item.children);
}
});
const onDelete = (key) => {
deleteNode(key, data);
setData([...data]);
};
//删除节点---接口
const deleteIds = async (key) => {
let data = await PostclubGoodsCategoryRemove({
ids: key,
})
if (data && data.code === 200) {
message.success('删除成功')
getDate();
}
}
const deleteNode = (key, data) =>
data.forEach((item, index) => {
if (item.key === key) {
if (!item.showAdd) {
deleteIds(key);
}
data.splice(index, 1);
return;
} else {
if (item.children) {
deleteNode(key, item.children);
}
}
});
return (
<div style={{
position: 'relative',
left: '-14px'
}}>
<Tree onExpand={onExpand} expandedKeys={expandedKeys}>
{renderTreeNodes(data)}
</Tree>
</div>
);
}
export default TreeData;