EditableTree.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import React, { useState } from "react";
  2. import { useEffect } from "react";
  3. import { Tree } from "antd";
  4. import type { DataNode, TreeProps } from "antd/es/tree";
  5. type TreeNodeData = {
  6. key: string;
  7. title: string;
  8. children: TreeNodeData[];
  9. level: number;
  10. };
  11. export type ListNodeData = {
  12. key: string;
  13. title: string;
  14. level: number;
  15. };
  16. var tocActivePath: TreeNodeData[] = [];
  17. function tocGetTreeData(articles: ListNodeData[], active = "") {
  18. let treeData = [];
  19. let treeParents = [];
  20. let rootNode: TreeNodeData = {
  21. key: "0",
  22. title: "root",
  23. level: 0,
  24. children: [],
  25. };
  26. treeData.push(rootNode);
  27. let lastInsNode: TreeNodeData = rootNode;
  28. let iCurrLevel = 0;
  29. for (let index = 0; index < articles.length; index++) {
  30. const element = articles[index];
  31. let newNode: TreeNodeData = {
  32. key: element.key,
  33. title: element.title,
  34. children: [],
  35. level: element.level,
  36. };
  37. /*
  38. if (active == element.article) {
  39. newNode["extraClasses"] = "active";
  40. }
  41. */
  42. if (newNode.level > iCurrLevel) {
  43. //新的层级比较大,为上一个的子目录
  44. treeParents.push(lastInsNode);
  45. lastInsNode.children.push(newNode);
  46. } else if (newNode.level === iCurrLevel) {
  47. //目录层级相同,为平级
  48. treeParents[treeParents.length - 1].children.push(newNode);
  49. } else {
  50. // 小于 挂在上一个层级
  51. while (treeParents.length > 1) {
  52. treeParents.pop();
  53. if (treeParents[treeParents.length - 1].level < newNode.level) {
  54. break;
  55. }
  56. }
  57. treeParents[treeParents.length - 1].children.push(newNode);
  58. }
  59. lastInsNode = newNode;
  60. iCurrLevel = newNode.level;
  61. if (active === element.key) {
  62. tocActivePath = [];
  63. for (let index = 1; index < treeParents.length; index++) {
  64. tocActivePath.push(treeParents[index]);
  65. }
  66. }
  67. }
  68. return treeData[0].children;
  69. }
  70. function treeToList(treeNode: TreeNodeData[]): ListNodeData[] {
  71. let iTocTreeCurrLevel = 1;
  72. let arrTocTree: ListNodeData[] = [];
  73. for (const iterator of treeNode) {
  74. getTreeNodeData(iterator);
  75. }
  76. function getTreeNodeData(node: TreeNodeData) {
  77. let children = 0;
  78. if (typeof node.children != "undefined") {
  79. children = node.children.length;
  80. }
  81. arrTocTree.push({
  82. key: node.key,
  83. title: node.title,
  84. level: iTocTreeCurrLevel,
  85. });
  86. if (children > 0) {
  87. iTocTreeCurrLevel++;
  88. for (const iterator of node.children) {
  89. getTreeNodeData(iterator);
  90. }
  91. iTocTreeCurrLevel--;
  92. }
  93. }
  94. return arrTocTree;
  95. }
  96. interface IWidgetEditableTree {
  97. treeData: ListNodeData[];
  98. onChange?: Function;
  99. }
  100. const Widget = ({ treeData, onChange }: IWidgetEditableTree) => {
  101. const data = tocGetTreeData(treeData);
  102. console.log("treedata", data);
  103. const [gData, setGData] = useState(data);
  104. useEffect(() => {
  105. const data = tocGetTreeData(treeData);
  106. setGData(data);
  107. }, [treeData]);
  108. const onDragEnter: TreeProps["onDragEnter"] = (info) => {
  109. console.log(info);
  110. // expandedKeys 需要受控时设置
  111. // setExpandedKeys(info.expandedKeys)
  112. };
  113. const onDrop: TreeProps["onDrop"] = (info) => {
  114. console.log(info);
  115. const dropKey = info.node.key;
  116. const dragKey = info.dragNode.key;
  117. const dropPos = info.node.pos.split("-");
  118. const dropPosition =
  119. info.dropPosition - Number(dropPos[dropPos.length - 1]);
  120. const loop = (
  121. data: DataNode[],
  122. key: React.Key,
  123. callback: (node: DataNode, i: number, data: DataNode[]) => void
  124. ) => {
  125. for (let i = 0; i < data.length; i++) {
  126. if (data[i].key === key) {
  127. return callback(data[i], i, data);
  128. }
  129. if (data[i].children) {
  130. loop(data[i].children!, key, callback);
  131. }
  132. }
  133. };
  134. const data = [...gData];
  135. // Find dragObject
  136. let dragObj: DataNode;
  137. loop(data, dragKey, (item, index, arr) => {
  138. arr.splice(index, 1);
  139. dragObj = item;
  140. });
  141. if (!info.dropToGap) {
  142. // Drop on the content
  143. loop(data, dropKey, (item) => {
  144. item.children = item.children || [];
  145. // where to insert 示例添加到头部,可以是随意位置
  146. item.children.unshift(dragObj);
  147. });
  148. } else if (
  149. ((info.node as any).props.children || []).length > 0 && // Has children
  150. (info.node as any).props.expanded && // Is expanded
  151. dropPosition === 1 // On the bottom gap
  152. ) {
  153. loop(data, dropKey, (item) => {
  154. item.children = item.children || [];
  155. // where to insert 示例添加到头部,可以是随意位置
  156. item.children.unshift(dragObj);
  157. // in previous version, we use item.children.push(dragObj) to insert the
  158. // item to the tail of the children
  159. });
  160. } else {
  161. let ar: DataNode[] = [];
  162. let i: number;
  163. loop(data, dropKey, (_item, index, arr) => {
  164. ar = arr;
  165. i = index;
  166. });
  167. if (dropPosition === -1) {
  168. ar.splice(i!, 0, dragObj!);
  169. } else {
  170. ar.splice(i! + 1, 0, dragObj!);
  171. }
  172. }
  173. setGData(data);
  174. if (typeof onChange !== "undefined") {
  175. onChange(treeToList(data));
  176. }
  177. };
  178. return (
  179. <>
  180. <Tree
  181. rootClassName="draggable-tree"
  182. draggable
  183. blockNode
  184. onDragEnter={onDragEnter}
  185. onDrop={onDrop}
  186. treeData={gData}
  187. />
  188. </>
  189. );
  190. };
  191. export default Widget;