原文地址:Building Recursive components in Vue
几天前,我想构建一个 Vue 组件,它能够显示嵌套节点树,但我们不知道确切的嵌套数量 - 因此它需要能够递归工作。我很惊讶网络上没有太多关于它的资源,所以我决定写一篇关于它的文章。
主要思想是让一个组件接受数据属性(目前数据结构未知)和另外两个属性用于summary
open
;第一个用于定义details
标签中使用的名称和显示的文本,第二个用于查看节点树是否打开。
我希望你会喜欢它:)
在 Vue 中构建递归组件
在此示例中,我使用 VueUse onClickOutside
工具函数来处理外部单击操作(我就是喜欢这个工具!)。
首先,让我们定义该组件将接受的 props:
const props = defineProps({ summary: { type: String, default: 'disclosure' }, open: { type: Boolean, default: false }, content: { type: Object, default: () => ({}) } })
接下来,让我们定义反应式引用和计算变量:
const computedOpenState = ref(props.open) const details = ref(null) const hasNestedChildren = computed(() => props.content.children?.length)
最后,在脚本标签的最后,让我们添加函数来处理切换细节和外部点击:
function toggleDetails(event: ToggleEvent) { computedOpenState.value = event.newState === 'open' } onClickOutside(details, () => (computedOpenState.value = false))
现在,让我们向组件添加一些模板。首先,如果嵌套内容没有更多嵌套子项,我们只想显示一个带有摘要名称的段落:
<p v-if="!hasNestedChildren"> {{ summary }} </p>
在其他情况下,我们想要利用 details
HTML 标签:
<p v-if="!hasNestedChildren"> {{ summary }} </p> <details v-else :open="computedOpenState" :name="summary" ref="details" @toggle="toggleDetails" > ... </details>
在 details
标签内,我们要添加以下代码来处理显示摘要和嵌套节点树:
<summary> {{ summary }} </summary> <template v-if="hasNestedChildren"> <NodeTree v-for="(child, key) in content.children" :key :summary="child.summary" :content="child" @click="toggleChildren" /> </template>
下面,您可以看到该组件的完整代码:
<script setup lang="ts"> import { onClickOutside } from '@vueuse/core' import { computed, ref } from 'vue' const props = defineProps({ summary: { type: String, default: 'disclosure' }, open: { type: Boolean, default: false }, content: { type: Object, default: () => ({}) } }) const computedOpenState = ref(props.open) const details = ref(null) const hasNestedChildren = computed(() => props.content.children?.length) function toggleDetails(event: ToggleEvent) { computedOpenState.value = event.newState === 'open' } onClickOutside(details, () => (computedOpenState.value = false)) </script> <template> <p v-if="!hasNestedChildren"> {{ summary }} </p> <details v-else ref="details" :open="computedOpenState" :name="summary" @toggle="toggleDetails" > <summary> {{ summary }} </summary> <template v-if="hasNestedChildren"> <NodeTree v-for="(child, key) in content.children" :key :summary="child.summary" :content="child" @click="toggleChildren" /> </template> </details> </template>
最后,该组件可以像下面这样使用:
<template> <NodeTree v-if="data" :content="data" :summary="data.summary" /> </template>
就是这样!您拥有完全正常工作的递归节点树组件:)
总结
干得好!您刚刚学习了如何构建递归 Vue 组件。
保重,下次再见!
And happy coding as always 🖥️