Skip to content

Commit 64afdb4

Browse files
committed
feat[ptr]: 组件递归 实现 层级列表组件 TreeListMenu
1 parent 0a2b4bb commit 64afdb4

4 files changed

Lines changed: 104 additions & 2 deletions

File tree

vue2/sandboxs/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"test:Lifecycle": "vue serve ./test/lifecycle/Lifecycle.vue",
1717
"test:FetchData":"vue serve ./test/lifecycle/FetchData.vue",
1818
"test:Loading": "vue serve ./src/components/Loading/test.vue",
19-
"test:vLoading": "vue serve ./src/directives/loading/test.vue"
19+
"test:vLoading": "vue serve ./src/directives/loading/test.vue",
20+
"test:TreeListMenu": "vue serve ./src/components/TreeListMenu/test.vue"
2021
},
2122
"dependencies": {
2223
"axios": "^1.13.4",
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<!--
2+
Vue 的 template 是静态的,不像 React ,如果想要实现嵌套结构
3+
1. 配置 render 函数
4+
2. 模版中递归
5+
-->
6+
7+
<template>
8+
<ul class="tree-list-menu-container">
9+
<li v-for="(item, index) in list" :key="index">
10+
<!-- 数据也不会经常变动 index ,设置 id 反而繁琐 -->
11+
<span :class="{ selected: item.isSelected }" @click="handleClick(item)">{{
12+
item.name
13+
}}</span>
14+
<TreeListMenu :list="item.children" @click="handleClick">
15+
<!-- 归的时候从子组件上抛的事件继续往上抛 -->
16+
</TreeListMenu>
17+
</li>
18+
</ul>
19+
</template>
20+
21+
<script>
22+
// 类似于广义表的递归结构 https://github.com/ceilf6/dataStructure/blob/main/learn2code/5-%E6%95%B0%E7%BB%84/%E5%B9%BF%E4%B9%89%E8%A1%A8/GenList.h
23+
// [ {name:"xxx", id: 1 ,isSelected: true, children:[ {name:"yyy", id: 2 ,isSelected: false} ] } ]
24+
function isTreeArray(arr) {
25+
return arr.every((item) => {
26+
return (
27+
typeof item.name === "string" &&
28+
// typeof item.id === "number" &&
29+
(!item.children || Array.isArray(item.children)) &&
30+
(!item.children || isTreeArray(item.children)) // 递归检查 children
31+
);
32+
});
33+
}
34+
35+
export default {
36+
name: "TreeListMenu", // 当前组件需要使用自己时,需要显式声明 name
37+
props: {
38+
list: {
39+
type: Array,
40+
default: () => [],
41+
validator(value) {
42+
return isTreeArray(value);
43+
},
44+
},
45+
},
46+
methods: {
47+
handleClick(item) {
48+
this.$emit("click", item);
49+
},
50+
},
51+
};
52+
</script>
53+
54+
<style scoped lang="less">
55+
@import "~@/styles/var.less";
56+
.tree-list-menu-container {
57+
list-style: none;
58+
padding: 0;
59+
.tree-list-menu-container {
60+
margin-left: 1em;
61+
}
62+
li {
63+
min-height: 40px;
64+
line-height: 40px;
65+
cursor: pointer;
66+
.selected {
67+
color: @warn;
68+
font-weight: bold;
69+
}
70+
}
71+
}
72+
</style>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<template>
2+
<TreeListMenu :list="list"></TreeListMenu>
3+
</template>
4+
5+
<script>
6+
import TreeListMenu from "./index.vue";
7+
export default {
8+
components: {
9+
TreeListMenu,
10+
},
11+
data() {
12+
return {
13+
list: [
14+
{ name: "1" }, // , isSelected: false },
15+
{
16+
name: "2",
17+
isSelected: false,
18+
children: [
19+
{ name: "2-1", isSelected: true, children: [{ name: "2-1-1" }] },
20+
],
21+
},
22+
{ name: "3", isSelected: false },
23+
{ name: "4", isSelected: false },
24+
],
25+
};
26+
},
27+
};
28+
</script>

vue2/sandboxs/src/components/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export { default as Layout } from './Layout'
33
export { default as Modal } from './Modal'
44
export { default as Pager } from './Pager'
55
export { default as ThreeColumnLayout } from './ThreeColumnLayout'
6-
export { default as Loading } from './Loading'
6+
export { default as Loading } from './Loading'
7+
export { default as TreeListMenu } from './TreeListMenu'

0 commit comments

Comments
 (0)