You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中构建一级项ID非空的树结构及Vue3下拉框适配

Vue3 实现排除选中节点及其后代的下拉选项方案

核心思路

无需预先构建完整树结构,直接通过找出需排除的节点集合(选中节点+所有多层子节点),再从原数组过滤掉这些节点,即可生成符合要求的下拉选项。这种方式比先构建树再处理更高效简洁。

实现步骤

1. 编写获取排除节点UUID的函数

通过迭代方式(避免递归栈溢出)找出选中节点的所有后代,将这些节点的UUID存入集合:

// 获取需排除的所有节点UUID(选中节点+所有多层后代)
function getExcludedUuids(selectedUuid, items) {
  const excluded = new Set([selectedUuid])
  // 初始化队列,放入选中节点的直接子节点
  const queue = [...items.filter(item => item.parentUUID === selectedUuid)]
  
  while (queue.length) {
    const currentNode = queue.shift()
    excluded.add(currentNode.uuid)
    // 将当前节点的子节点加入队列,继续遍历
    queue.push(...items.filter(item => item.parentUUID === currentNode.uuid))
  }
  
  return excluded
}

2. 在Vue3组件中集成逻辑

结合计算属性,实时根据选中节点过滤下拉选项:

<template>
  <div>
    <!-- 树视图组件,选中节点时触发节点更新 -->
    <TreeView @node-select="handleNodeSelect" :items="rawTreeItems" />
    
    <!-- 下拉选择框 -->
    <select v-model="selectedDropdownValue">
      <option 
        v-for="item in filteredDropdownItems" 
        :key="item.uuid" 
        :value="item.uuid"
      >
        {{ item.name }}
      </option>
    </select>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

// 原始树结构数据,格式为 { uuid: string, parentUUID: string|null, name: string }
const rawTreeItems = ref([
  { uuid: 'root-1', parentUUID: null, name: '根节点1' },
  { uuid: 'child-1-1', parentUUID: 'root-1', name: '子节点1-1' },
  { uuid: 'child-1-1-1', parentUUID: 'child-1-1', name: '孙节点1-1-1' },
  { uuid: 'root-2', parentUUID: null, name: '根节点2' }
])

// 存储选中的树节点UUID
const selectedNodeUuid = ref(null)

// 计算属性:过滤出符合条件的下拉选项
const filteredDropdownItems = computed(() => {
  if (!selectedNodeUuid.value) return rawTreeItems.value
  
  const excludedUuids = getExcludedUuids(selectedNodeUuid.value, rawTreeItems.value)
  return rawTreeItems.value.filter(item => !excludedUuids.has(item.uuid))
})

// 树节点选中事件回调
function handleNodeSelect(node) {
  selectedNodeUuid.value = node.uuid
}

// 复用之前定义的排除节点函数
function getExcludedUuids(selectedUuid, items) {
  const excluded = new Set([selectedUuid])
  const queue = [...items.filter(item => item.parentUUID === selectedUuid)]
  
  while (queue.length) {
    const currentNode = queue.shift()
    excluded.add(currentNode.uuid)
    queue.push(...items.filter(item => item.parentUUID === currentNode.uuid))
  }
  
  return excluded
}
</script>

3. 大数据量优化

如果原始数据量较大,重复遍历数组找子节点会影响性能,可以预先构建父UUID到子节点的映射表,优化查找效率:

// 构建父UUID到子节点的映射表
function buildParentChildMap(items) {
  const map = new Map()
  items.forEach(item => {
    if (!map.has(item.parentUUID)) {
      map.set(item.parentUUID, [])
    }
    map.get(item.parentUUID).push(item)
  })
  return map
}

// 优化版的排除节点函数
function getExcludedUuidsOptimized(selectedUuid, parentMap) {
  const excluded = new Set([selectedUuid])
  const queue = parentMap.get(selectedUuid) || []
  
  while (queue.length) {
    const currentNode = queue.shift()
    excluded.add(currentNode.uuid)
    queue.push(...(parentMap.get(currentNode.uuid) || []))
  }
  
  return excluded
}

在组件中使用优化版:

// 计算属性生成映射表
const parentChildMap = computed(() => buildParentChildMap(rawTreeItems.value))

// 更新下拉选项的计算属性
const filteredDropdownItems = computed(() => {
  if (!selectedNodeUuid.value) return rawTreeItems.value
  
  const excludedUuids = getExcludedUuidsOptimized(selectedNodeUuid.value, parentChildMap.value)
  return rawTreeItems.value.filter(item => !excludedUuids.has(item.uuid))
})

内容的提问来源于stack exchange,提问作者tesicg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 23:37:49