Dust8 的博客

读书百遍其义自见

0%

vue之组合式函数

起因

前端有个树形结构需要显示, 层级比较多, 达到7层, 还是需要自适应大小. 现有的组件要不层级不够, 例如像省市县这样的级联, 只有3层, 如果做成7层, 在移动端显示效果不好.
在网上发现yangjingyu/vs-tree比较符合要求, 上面用面包屑显示层级, 下面只显示最后一层的列表. 不过在vue3上有些问题. 刚好最近接触了hooks, 还了解了Headless UI. 把逻辑和ui进行分离, 以前看过(用积木理论设计一个灵活好用的Carousel走马灯组件), 也想过, 只是不知道这样一个统一的名称.
目前常见的组件通过slot来定制化还是不够灵活.
灵活性:

1
手写逻辑和ui > hooks + 手写ui > ui框架组件

当然灵活性越大, 工作量也越大.

实例

输入: data 是一个扁平的树, id为”_”的是根节点.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"_": {
"id": "_",
"name": "_",
"children": ["1", "2"]
},
"1": {
"id": "1",
"name": "1",
"children": []
},
"2": {
"id": "2",
"name": "2",
"children": []
}
}

输出: 导出4个变量, breadcrumbNodes,breadcrumbNodeClick,是上面面包屑的节点列表, 和点击函数, currentNodes, currentNodeClick 是下面的节点列表和点击函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# useTree.js
import { ref } from "vue";

const useTree = (data) => {
const nodesMap = ref(data);
const breadcrumbNodes = ref([]);
const currentNodes = ref([]);

const updateCurrentNodes = (node) => {
const nodes = [];
nodesMap.value[node.id].children.forEach((element) => {
nodes.push(nodesMap.value[element]);
});
currentNodes.value = nodes;
};
const breadcrumbNodeClick = (index) => {
// 更新头
breadcrumbNodes.value = breadcrumbNodes.value.slice(0, index + 1);

// 更新列表
const node = breadcrumbNodes.value[index];
updateCurrentNodes(node);
};

const currentNodeClick = (index) => {
const node = currentNodes.value[index];
if (!node.children || !node.children.length) {
console.log("no children");
return;
}

// 更新头
breadcrumbNodes.value.push(node);

// 更新列表
updateCurrentNodes(node);
};

breadcrumbNodes.value.push(nodesMap.value["_"]);
updateCurrentNodes(nodesMap.value["_"]);

return {
breadcrumbNodes,
currentNodes,
breadcrumbNodeClick,
currentNodeClick,
};
};
export default useTree;

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<script setup>
import useTree from './useTree'

const data2 = {}
const { breadcrumbNodes, currentNodes, breadcrumbNodeClick, currentNodeClick } = useTree(data2)

const listclick2 = (index) => {
const node = currentNodes.value[index]
console.log('listclick2', index, node.name)
currentNodeClick(index)
}

</script>
<template>
<div>
<div class="tree-box">
<div class="tree-breadcrumb">
<span v-for="(item, index) in breadcrumbNodes" :key="item.id" @click="breadcrumbNodeClick(index)">
<span class="tree-breadcrumb-start" v-if="index == 0">@</span>
<span class="tree-breadcrumb-link">{{ item.name }}</span>
<span class="tree-breadcrumb-separator" v-if="index != breadcrumbNodes.length - 1">/</span>
</span>
</div>

<ul class="tree-list">
<li v-for="(item, index) in currentNodes" :key="item.id" @click="listclick2(index)">
{{ item.name }}
</li>
</ul>
</div>
</div>
</template>

参考链接