我们在日常工作中处理大量嵌套数据。一个常见的用例是创建一个 n 级别的切换列表。让我们尝试使用 Vue 3 组合 API 的递归来创建这样一个值列表。

我们将在这条线上创造一些东西。

menu.gif

开始使用

首先,我们可以先定义我们的菜单结构。重要的是,只有当我们可以将菜单中的每个级别都视为相同时,递归才会起作用,这意味着它应该一直具有相同的结构。为此,我们可以决定每个菜单项都有一个标题和一组子项。这些孩子中的每一个都将遵循相同的格式,一直向下。

对于这篇文章,我们将使用以下菜单结构:

- Item 1
  - Item 1.1
    - Item 1.1.1
  - Item 1.2
- Item 2
  - Item 2.1

让我们创建一个对象数组,如下所示。

const menu = [
  {
    title: 'Item 1',
    children: [
      {
        title: 'Item 1.1',
        children: [
          {
            title: 'Item 1.1.1',
          },
        ],
      },
      {
        title: 'Item 1.2',
      },
    ],
  },
  {
    title: 'Item 2',
    children: [
      {
        title: 'Item 2.1',
      },
    ],
  },
];

# 创建组件

现在让我们创建顶级组件。它将菜单作为道具并将列表显示为 li 元素。

//App.vue
<script setup>
import { ref, defineProps} from 'vue'

import Menu from './Menu.vue'

import {menu} from './menu';

</script>

<template>
 <Menu :menu="menu"></Menu>
</template>
//Menu.vue
<script setup>
import { ref } from 'vue'

const props = defineProps({
  menu: Array
})

</script>

<template>
  <ul>
     <template v-for="(item, index) in menu" :key="ite.title">
          <li>{{item.title}}</li>
      </template>
  </ul>
</template>

在 Menu 组件中,我们将遍历菜单数组中的每个项目,并在列表项中显示每个项目的标题。到目前为止所有的 Vue!

嵌套列表

下一个挑战是基于子数组的嵌套列表。

但这里似乎并不难。如果有子数组,我们可以检查是否在列表中创建另一个组件。

<template>
  <ul >
    <template v-for="(item, index) in menu" :key="index">
      <li>{{item.title}}
    <Menu v-if="item.children :menu="item.children"></Menu>
    </li>
      </template>
  </ul>
</template>

它应该看起来像这样。

recurse.png.

欢呼。我们已经创建了一个菜单。 Vue 多么简单。

切换实现

可是等等。如果列表增加,这看起来会很混乱。因此,我们可以尝试创建简单的切换按钮来展开和折叠列表项。

//Menu.vue
<script setup>
import { ref } from 'vue'


const msg = ref('Hello World!')

const expansionState = ref({});

const updateExpansion = (node) => {
    expansionState.value[node] = !expansionState.value[node]
}

const props = defineProps({
  menu: Array
})

</script>

<template>
  <ul >
    <template v-for="(item, index) in menu" :key="index">
      <li>{{item.title}}
      <button v-if="item.children" @click="updateExpansion(item.title)">
        {{ expansionState[item.title] ? '-' : '+' }}
      </button>
    <Menu v-if="item.children && expansionState[item.title]" :menu="item.children"></Menu>
    </li>
      </template>
  </ul>
</template>

令人困惑的是。让我们分解一下。

为了跟踪每个节点的扩展状态,我们创建了一个 expansionState 反应对象。这将在切换按钮的展开和折叠时切换。

当我们开始时,我们的每个 Menu 组件都会将 expandState 设置为 {}。 .如果单击顶层项目 1 旁边的 + 按钮,则扩展状态状态现在将等于 { "Item 1": true }。这将是有状态的 expandState 对象在我们菜单的每个级别上的工作方式!。

我们在这里有最终的简单切换菜单列表。

menu.gif

最后的想法

我知道这方面可以有很多改进,但这绝对可以作为一个起点。下一篇文章见。

神速,贾西尔

Logo

前往低代码交流专区

更多推荐