Browse Source

目录支持层级

visuddhinanda 2 years ago
parent
commit
47073a6d60
1 changed files with 102 additions and 14 deletions
  1. 102 14
      dashboard/src/components/article/AnchorNav.tsx

+ 102 - 14
dashboard/src/components/article/AnchorNav.tsx

@@ -1,38 +1,126 @@
 import { Anchor } from "antd";
-import lodash from "lodash";
 import { useEffect, useState } from "react";
 const { Link } = Anchor;
 
 interface IHeadingAnchor {
   label: string;
   key: string;
+  level: number;
+  children?: IHeadingAnchor[];
 }
+
+function tocGetTreeData(
+  listData: IHeadingAnchor[],
+  active = ""
+): IHeadingAnchor[] | undefined {
+  let treeData: IHeadingAnchor[] = [];
+  let tocActivePath: IHeadingAnchor[] = [];
+  let treeParents = [];
+  let rootNode: IHeadingAnchor = {
+    key: "0",
+    label: "root",
+    level: 0,
+    children: [],
+  };
+  treeData.push(rootNode);
+  let lastInsNode: IHeadingAnchor = rootNode;
+
+  let iCurrLevel = 0;
+  for (let index = 0; index < listData.length; index++) {
+    const element = listData[index];
+
+    let newNode: IHeadingAnchor = {
+      key: element.key,
+      label: element.label,
+      level: element.level,
+    };
+
+    if (newNode.level > iCurrLevel) {
+      //新的层级比较大,为上一个的子目录
+      treeParents.push(lastInsNode);
+      if (typeof lastInsNode.children === "undefined") {
+        lastInsNode.children = [];
+      }
+      lastInsNode.children.push(newNode);
+    } else if (newNode.level === iCurrLevel) {
+      //目录层级相同,为平级
+      const parentNode = treeParents[treeParents.length - 1];
+      if (typeof parentNode !== "undefined") {
+        if (typeof parentNode.children === "undefined") {
+          parentNode.children = [];
+        }
+        parentNode.children.push(newNode);
+      }
+    } else {
+      // 小于 挂在上一个层级
+      while (treeParents.length > 1) {
+        treeParents.pop();
+        if (treeParents[treeParents.length - 1].level < newNode.level) {
+          break;
+        }
+      }
+      const parentNode = treeParents[treeParents.length - 1];
+      if (typeof parentNode !== "undefined") {
+        if (typeof parentNode.children === "undefined") {
+          parentNode.children = [];
+        }
+        parentNode.children.push(newNode);
+      }
+    }
+    lastInsNode = newNode;
+    iCurrLevel = newNode.level;
+
+    if (active === element.key) {
+      tocActivePath = [];
+      for (let index = 1; index < treeParents.length; index++) {
+        //treeParents[index]["expanded"] = true;
+        tocActivePath.push(treeParents[index]);
+      }
+    }
+  }
+
+  return treeData[0].children;
+}
+
 interface IWidget {
   content?: string;
   open?: boolean;
 }
 const AnchorNavWidget = ({ open = false, content }: IWidget) => {
-  const [heading, setHeading] = useState<IHeadingAnchor[]>([]);
+  const [heading, setHeading] = useState<IHeadingAnchor[]>();
 
   useEffect(() => {
     let heading = document.querySelectorAll("h1,h2,h3,h4,h5,h6");
     let headingAnchor: IHeadingAnchor[] = [];
     for (let index = 0; index < heading.length; index++) {
       const element = heading[index];
-      const id = lodash
-        .times(20, () => lodash.random(35).toString(36))
-        .join("");
-      heading[index].id = id;
-      headingAnchor.push({ key: `#${id}`, label: element.innerHTML });
+      const id = heading[index].id;
+      if (id) {
+        console.log("level", heading[index].tagName);
+        const level = parseInt(heading[index].tagName.replace("H", ""));
+        headingAnchor.push({
+          key: `#${id}`,
+          label: element.innerHTML,
+          level: level,
+        });
+      }
     }
-    setHeading(headingAnchor);
+    setHeading(tocGetTreeData(headingAnchor));
+    console.log("heading", headingAnchor);
   }, [open]);
-  return open ? (
-    <Anchor offsetTop={50}>
-      {heading.map((item, index) => {
-        return <Link key={index} href={item.key} title={item.label}></Link>;
-      })}
-    </Anchor>
+
+  const GetLink = (anchors: IHeadingAnchor[]) => {
+    return anchors.map((it, id) => {
+      return (
+        <Link key={id} href={it.key} title={it.label}>
+          {it.children ? GetLink(it.children) : undefined}
+        </Link>
+      );
+    });
+  };
+
+  return open && heading ? (
+    <Anchor offsetTop={50}>{GetLink(heading)}</Anchor>
   ) : (
     <></>
   );