如何使用 Vue 实现无限级列表?

1. 什么是无限级列表?

无限级列表,又称无限层级列表,是指可以展示无限深度的多层级树形结构。最常见的应用场景包括商品分类、地区选择、组织架构等多种业务场景中。

在无限级列表中,每个节点都可以有任意数量的子节点,因此可以实现非常复杂的数据展示和交互需求。

2. Vue 是什么?

Vue.js 是一套构建用户界面的渐进式框架,与 React、Angular 等框架相比,它相对较小、易上手、易扩展,是当前业内最流行的前端框架之一。

3. 使用 Vue 实现无限级列表的步骤

3.1 结构分析

在实现无限级列表之前,我们需要先了解数据的结构和组件的拆分,把整个页面划分为多个组件,以便于维护和复用。

下面是一个简单的数据结构示意图:

{

label: '节点1',

children: [

{

label: '节点1-1',

children: [

{

label: '节点1-1-1',

children: []

}

]

},

{

label: '节点1-2',

children: []

}

]

}

该数据结构由多个节点组成,每个节点包含两个字段:label 字段表示当前节点的文本内容,children 字段表示当前节点的子节点数组,如果 children 是空数组,则表示当前节点为叶子节点。

在组件拆分方面,我们可以将整个无限级列表划分为三个组件:

TreeView:整个树形结构组件,负责渲染节点和展开/折叠状态

TreeNode:树形节点组件,负责渲染节点文本和子节点

TreeLoading:树形节点加载中组件,负责在子节点异步加载时显示加载中状态

3.2 渲染树形结构

在 TreeView 组件中,我们通过递归的方式实现对整个树形结构的渲染:

<template>

<ul class="tree">

<li v-for="(node, index) in treeData" :key="index">

<tree-node :node="node" @toggle="toggleNode"></tree-node>

</li>

</ul>

</template>

<script>

import TreeNode from './TreeNode'

export default {

name: 'TreeView',

components: {

TreeNode

},

props: {

treeData: {

type: Array,

required: true

}

},

methods: {

toggleNode(node) {

node.expanded = !node.expanded

}

}

}

</script>

其中,treeData 是树形结构的根节点数组,通过 v-for 指令进行渲染,每个节点通过 <tree-node> 组件进行递归渲染。

在 toggleNode 方法中,我们通过修改 expanded 属性来控制节点的展开和折叠状态。

3.3 渲染树形节点

在 TreeNode 组件中,我们通过递归的方式实现对整个树形节点的渲染:

<template>

<div class="tree-node">

<span class="label" :class="{ 'has-children': hasChildren }" @click="handleClick">

<i v-if="hasChildren" class="icon" :class="{ 'icon-fold': node.expanded, 'icon-unfold': !node.expanded }"></i>

{{ node.label }}

</span>

<ul v-if="node.expanded">

<li v-for="(childNode, index) in node.children" :key="index">

<tree-node :node="childNode" @toggle="$emit('toggle', childNode)"></tree-node>

</li>

<tree-loading v-if="node.loading"></tree-loading>

</ul>

</div>

</template>

<script>

import TreeLoading from './TreeLoading'

export default {

name: 'TreeNode',

components: {

TreeLoading

},

props: {

node: {

type: Object,

required: true

}

},

computed: {

hasChildren() {

return this.node.children && this.node.children.length > 0

}

},

methods: {

handleClick() {

if (this.hasChildren) {

if (!this.node.expanded && this.node.children.length === 0) {

this.loadChildren()

} else {

this.$emit('toggle', this.node)

}

}

},

async loadChildren() {

this.node.loading = true

// 省略异步加载子节点的逻辑

await this.$nextTick()

this.node.expanded = true

this.node.loading = false

}

}

}

</script>

其中,node 属性表示当前节点,通过 <span class="label"> 渲染节点的文本内容,通过计算属性 hasChildren 判断当前节点是否有子节点。

在 handleClick 方法中,我们通过判断节点是否有子节点来决定是展开还是折叠节点。如果该节点已经展开过或者没有子节点,则直接切换节点的展开/折叠状态。如果该节点没有展开过并且有子节点,则显示加载中状态并异步加载子节点,加载完成后自动展开该节点。

在 loadData 方法中,我们通过设置 loading 属性来显示加载中状态,然后通过异步请求获取子节点数据,加载完成后将数据设置到节点的 children 属性上,并将 loading 状态设置为 false。

3.4 渲染树形节点加载中状态

在 TreeLoading 组件中,我们简单地显示一个加载中的图标:

<template>

<div class="tree-loading">

<span class="loading-text">加载中...</span>

</div>

</template>

<script>

export default {

name: 'TreeLoading'

}

</script>

4. 完整代码

下面是基于 Vue 实现无限级列表的完整代码:

在线演示

GitHub 仓库

5. 总结

无限级列表是前端开发中常见的数据展示方式,通过 Vue 框架可以轻松地实现该功能。在实现无限级列表时,我们需要考虑数据的结构和组件的拆分,以便于代码的维护和复用。同时,通过异步加载子节点,可以实现更好的用户体验。