트리구조

developer.do·2023년 5월 16일
0
post-custom-banner
const menuAddPopupIsOpen = ref<boolean>(false);
const menusData = ref<IData[]>([]);

const inquiryMenus = async () => {
  try {
    const res = await axios.get("/api/v1/menus");
    menusData.value = res.data.body.data;
    console.log(menusData.value);
  } catch (error) {
    console.error("MenuList.vue error / inquiryMenus error" + error);
  }
};

class TreeNode {
  data: IData;
  label: string;
  parent: TreeNode | null;
  children: TreeNode[];

  constructor(data: IData) {
    this.data = data;
    this.parent = null;
    this.children = [];
    this.label = data.menuName;
  }

  insertChild(node: TreeNode) {  // (노드기준)만약 내 parentId가 부모 노드의 id와 같다면(meuuId) 나는 그 부모 노트의 children으로 들어감
    // 만약 내 parentId가 null 이라면 result 다음 index로 추가가 된다. 
    // 만약 내 parentId가 menu_01이라면 
    // 만약 내 parentId가 
    this.children.push(node);
  }

  static isParentNode(parent: TreeNode, child: TreeNode): boolean {
    return parent.data.menuId === child.data.parentId;
  }

  addTreeToParent(target: TreeNode): TreeNode | null {  // 내가 부모라면 자식목록에 넣고 나를 리턴한다. 내가 부모가아니면 내 자식들한테 니가 부모해라 물어보겠지, 그래서 계속 자식한테 물어봄
    if (TreeNode.isParentNode(this, target)) {
      this.insertChild(target);
      return this;
    }

    for (let i = 0; i < this.children.length; i++) {  // 자기 자식도 없고 더이상 물어볼 애도 없다. 그러면 null을 반환한다.
      const existParent: any = this.children[i].addTreeToParent(target); // 부모 노드에서 일치하는 id가 없다면 그러면 그 밑의 children의 id와 일치하고 맞으면 거기에 밑으로 들어간다.
      if (existParent) {
        return existParent;
      }
    }
    return null;
  }
}

let newTreeArrData = reactive<TreeNode[]>([]);
watch(
  () => menusData.value,
  (newVal) => {
    console.log("newVal menus data: " + newVal);
    apiToTree();
    console.log("newTreeArrData: ", newTreeArrData);
    treeToData();
    console.log("treeToData: ", result.value);
  },
  { deep: true }
);

function apiToTree() { // 1. 여기가 진입점임
  newTreeArrData = [];
  for (let i = 0; i < menusData.value.length; i++) {  // 부모 id가 없으면 최상위 노드니깐 바로 잡아버린다.
    const data = menusData.value[i];
    const currNode = new TreeNode(data);

    if (!data.parentId) {
      newTreeArrData.push(currNode);
      console.info("currNode is top", currNode.data.menuId);
      continue;
    }

    let added = false;  // 모든 루트 노드를 돌았으면 에러가 나야함
    for (let i = 0; i < newTreeArrData.length; i++) {
      const exist = newTreeArrData[i];
      const parent = exist.addTreeToParent(currNode); // 루트 노드들에서 재귀함수를 실행시킨다.(각각의 트리 함수들을 실행시킨다.)
      if (parent) break; // 모든 루트 노드들을 돌면서 자식들이 있는지 확인하고 없으면 애러를 준다. 
    }
    if (!added) {
      console.log("not added any nodes", currNode.data);
    }
  }
  console.log(newTreeArrData);
}

interface TreeData {
  label: string;
  children: TreeData[];
}
const toTreeData = (tree: TreeNode): TreeData => {
  return {
    label: tree.label,
    children: tree.children.map((x) => toTreeData(x)).flat(),
  };
};
let result = ref<TreeData[]>([]); // 
function treeToData() {
  result.value = newTreeArrData.map(toTreeData);
}

const handleNodeClick = (data: IData) => {
  console.log(data);
};

const defaultProps = {
  children: "children",
  label: "label",
};

const menuAddPopupOpen = () => {
  menuAddPopupIsOpen.value = true;
};

onMounted(() => {
  inquiryMenus();
});
</script>
post-custom-banner

0개의 댓글