npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue3-super-tree

v1.4.3

Published

一个功能强大、高度可定制的 Vue 3 树形组件,完全复刻 PrimeVue Tree 的功能特性,支持拖拽、多选、键盘导航等高级功能

Readme

Vue3 Super Tree

npm version npm downloads GitHub license TypeScript Build Status Production Ready

一个功能强大、高度可定制的 Vue 3 树形组件 npm 包,完全复刻 PrimeVue Tree 的功能特性,支持拖拽、多选、键盘导航等高级功能。

📄 协议

本项目采用 MIT 协议 开源,您可以自由使用、修改和分发本项目。

🆕 v1.4.3 更新亮点

🔍 拖拽功能调试和诊断增强

  • 新增拖拽测试页面 - 添加了专门的 DragTestPage.vue,提供完整的拖拽功能测试和调试环境
  • 增强事件日志记录 - 改进了拖拽事件的详细日志记录,包含完整的事件数据和时间戳
  • 实时调试信息 - 提供实时的拖拽状态显示,包括 isDragDropEnabled 状态和拖拽配置信息
  • 操作指导优化 - 添加了详细的拖拽操作指导和最佳实践说明

📚 文档和集成支持完善

  • 集成指南文档 - 新增 INTEGRATION_GUIDE.md,提供详细的外部项目集成指南
  • 故障排除文档 - 新增 TROUBLESHOOTING.md,包含常见问题和解决方案
  • 外部项目示例 - 新增 EXTERNAL_PROJECT_EXAMPLE.md,提供完整的外部项目使用示例
  • 发布说明文档 - 新增 RELEASE_NOTES_1.4.3.md,详细记录版本更新内容

🛠️ 开发体验提升

  • 调试工具增强 - 提供更好的调试工具和测试按钮,帮助开发者快速验证拖拽配置
  • 错误诊断改进 - 增强了拖拽功能的错误诊断能力,提供更准确的问题定位
  • 配置验证 - 添加了配置参数的实时验证和反馈机制

🆕 v1.4.2 更新亮点

🔧 跨树拖拽功能重大修复

  • 修复跨树拖拽核心问题 - 解决了 performCrossTreeDrop 返回值检查逻辑错误,确保跨树拖拽操作正确执行
  • 完善拖拽属性配置 - 为 Tree 组件添加了缺失的 dragdrop-scope 属性支持,修复了 isDragDropEnabled 计算属性逻辑
  • 简化演示代码架构 - 重构 TreeDemo.vue 中的跨树拖拽演示,移除复杂的手动数据处理逻辑
  • 组件内部自动化 - 现在跨树拖拽完全由组件内部自动处理,用户只需简单配置即可使用
  • 提升开发体验 - 大幅简化了跨树拖拽的使用方式,减少了样板代码和配置复杂度

🆕 v1.4.1 更新亮点

🐛 演示页面拖拽功能修复

  • 修复 TreeDemo.vue 拖拽排序功能 - 为拖拽排序的 Tree 组件添加了缺少的 :dragdrop="true" 属性
  • 修复 TreeDemo.vue 跨树拖拽功能 - 为跨树拖拽的两个 Tree 组件添加了 :dragdrop="true":crossTreeAutoUpdate="false" 属性
  • 确保演示功能正常工作 - 修复了演示页面中拖拽功能的配置问题,用户现在可以正常体验所有拖拽特性
  • 配置一致性 - 统一了拖拽相关属性的配置,确保文档示例与实际代码保持一致

🆕 v1.4.0 更新亮点

🔧 构建稳定性大幅提升

  • 44个构建错误全部修复 - 完成了大规模的 TypeScript 类型系统重构,确保构建过程零错误
  • 生产就绪状态 - 库文件构建稳定,支持 ES 模块和 UMD 两种格式,完整的类型定义文件
  • TypeScript 类型安全 - 完善的类型定义,确保开发时的类型安全和 IDE 智能提示

🚀 功能完整性和稳定性

  • 跨树拖拽自动更新功能完整集成 - 将 TreeDemo 中的高级跨树拖拽功能完全集成到插件核心,提供开箱即用的跨树拖拽体验
  • CrossTreeDataProvider 接口 - 新增跨树数据提供者接口,支持灵活的数据源管理和自定义数据更新逻辑
  • 增强的拖拽状态管理 - 新增 useCrossTreeDragState 全局状态管理,确保跨树拖拽状态的一致性和可靠性
  • 完善的错误处理 - 修复所有关键运行时错误,提升组件稳定性和可靠性

🏗️ 架构优化

  • 插件化架构优化 - 所有跨树拖拽功能现已完全集成到插件核心,符合插件规范,无需额外配置
  • 性能优化 - 生产构建自动移除调试日志,优化包体积和运行性能
  • 开发体验提升 - 完整的开发工具支持,热重载,类型检查等

🚀 特性

核心功能

  • 完整的树形结构支持 - 支持无限层级的树形数据展示,经过大规模测试验证
  • 多种选择模式 - 支持单选、多选、复选框选择,状态管理稳定可靠
  • 拖拽功能 - 支持节点拖拽排序和跨树拖拽,包含完整的错误处理和状态恢复
  • 键盘导航 - 完整的键盘快捷键支持,符合无障碍访问标准
  • 懒加载 - 支持大数据量的懒加载展示,性能优化到位
  • 过滤搜索 - 内置过滤器,支持自定义过滤逻辑,搜索性能优异

高级功能

  • 跨树拖拽自动更新 - 全新的自动更新模式,支持多个树组件之间的智能数据同步
  • CrossTreeDataProvider 接口 - 灵活的数据提供者模式,支持自定义数据源和更新逻辑
  • 全局状态管理 - useCrossTreeDragState 提供一致的跨组件状态管理
  • 调试和诊断工具 - 内置的拖拽测试页面和实时调试信息,帮助快速定位问题
  • 自定义模板 - 支持节点内容、图标、展开/折叠图标的自定义
  • 事件系统 - 丰富的事件回调,包含完整的错误处理和状态追踪
  • 主题定制 - 支持自定义样式和主题,CSS 变量支持

技术特性

  • Vue 3 Composition API - 基于最新的 Vue 3 技术栈,充分利用响应式系统
  • TypeScript 完全支持 - 100% TypeScript 编写,完整的类型安全支持,零类型错误
  • 生产就绪 - 经过严格测试,44个构建错误全部修复,稳定可靠
  • Tree Shaking - 支持按需引入,优化包体积,生产构建自动优化
  • SSR 友好 - 支持服务端渲染,同构应用兼容
  • 零外部依赖 - 除 Vue 3 外无其他依赖,减少包体积和潜在冲突

📋 版本信息

当前最新版本:v1.4.3

本版本是一个功能增强版本,主要改进内容:

  • 新增了专门的拖拽测试页面,提供完整的调试和诊断环境
  • 增强了拖拽事件的日志记录和实时状态显示功能
  • 完善了集成指南、故障排除和外部项目示例文档
  • 提升了开发体验,添加了更好的调试工具和配置验证
  • 改进了错误诊断能力,帮助开发者快速定位和解决问题

v1.4.2 版本主要修复:

  • 修复了跨树拖拽功能的核心问题,解决了 performCrossTreeDrop 返回值检查逻辑错误
  • 完善了 Tree 组件的拖拽属性配置,添加了缺失的 dragdrop-scope 属性支持
  • 修复了 isDragDropEnabled 计算属性的逻辑,确保拖拽功能正确启用
  • 重构并简化了 TreeDemo.vue 中的跨树拖拽演示代码
  • 移除了复杂的手动数据处理逻辑,现在完全由组件内部自动处理
  • 大幅提升了跨树拖拽功能的易用性和稳定性

v1.4.1 版本主要改进:

  • 修复了 TreeDemo.vue 中拖拽排序功能的配置问题
  • 修复了 TreeDemo.vue 中跨树拖拽功能的配置问题
  • 为 Tree 组件添加了缺少的 :dragdrop="true" 属性
  • 为跨树拖拽添加了 :crossTreeAutoUpdate="false" 属性
  • 确保演示页面中的拖拽功能正常工作

v1.4.0 版本主要改进:

  • 完整集成跨树拖拽自动更新功能到插件核心
  • 新增 CrossTreeDataProvider 接口,支持灵活的数据源管理
  • 增强拖拽状态管理,新增全局状态管理机制
  • 修复关键错误,提升组件稳定性和可靠性
  • 优化插件化架构,所有功能完全集成到核心

🏗️ 构建状态

构建信息

  • 构建状态: ✅ 通过 (44个错误已修复)
  • 类型检查: ✅ 完全通过
  • 生产就绪: ✅ 是
  • 包格式: ES 模块 + UMD
  • 类型定义: 完整的 .d.ts 文件

性能指标

  • 包体积: 优化后的生产构建
  • Tree Shaking: ✅ 支持
  • 调试日志: 生产环境自动移除
  • 依赖: 零外部依赖 (除 Vue 3)

质量保证

  • TypeScript: 100% 类型安全
  • 错误处理: 完整的错误边界
  • 状态管理: 稳定的响应式状态
  • 测试覆盖: 核心功能全覆盖

📦 安装

# 使用 npm
npm install vue3-super-tree

# 使用 yarn
yarn add vue3-super-tree

# 使用 pnpm
pnpm add vue3-super-tree

🚀 快速开始

基础使用

<template>
  <div>
    <Tree 
      :value="nodes" 
      :selectionMode="'single'"
      v-model:selectionKeys="selectedKeys"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const nodes = ref([
  {
    key: '0',
    label: '根节点',
    children: [
      {
        key: '0-0',
        label: '子节点 1'
      },
      {
        key: '0-1',
        label: '子节点 2'
      }
    ]
  }
])

const selectedKeys = ref({})
</script>

完整功能示例

<template>
  <div>
    <Tree 
      :value="nodes"
      :selectionMode="'multiple'"
      :filter="true"
      :dragdrop="true"
      :loading="loading"
      v-model:selectionKeys="selectedKeys"
      v-model:expandedKeys="expandedKeys"
      @node-select="onNodeSelect"
      @node-unselect="onNodeUnselect"
      @node-expand="onNodeExpand"
      @node-collapse="onNodeCollapse"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const nodes = ref([...]) // 你的树形数据
const selectedKeys = ref({})
const expandedKeys = ref({})
const loading = ref(false)

const onNodeSelect = (node) => {
  console.log('节点选中:', node)
}

const onNodeUnselect = (node) => {
  console.log('节点取消选中:', node)
}

const onNodeExpand = (node) => {
  console.log('节点展开:', node)
}

const onNodeCollapse = (node) => {
  console.log('节点折叠:', node)
}
</script>

TypeScript 支持

import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import type { TreeNode, TreeSelectionKeys, TreeExpandedKeys } from 'vue3-super-tree/types'
import 'vue3-super-tree/style.css'

const nodes = ref<TreeNode[]>([
  {
    key: '0',
    label: '根节点',
    children: [...]
  }
])

const selectedKeys = ref<TreeSelectionKeys>({})
const expandedKeys = ref<TreeExpandedKeys>({})

📖 API 文档

Tree 组件属性

| 属性 | 类型 | 默认值 | 描述 | |------|------|--------|------| | value | TreeNode[] | [] | 树形数据,支持无限层级嵌套 | | modelValue | TreeSelectionKeys | null | 选中的节点(v-model),支持双向绑定 | | selectionMode | 'single' \| 'multiple' \| 'checkbox' | null | 选择模式:单选、多选或复选框模式 | | selectionKeys | TreeSelectionKeys | {} | 选中状态对象,键为节点 key,值为选中状态 | | expandedKeys | TreeExpandedKeys | {} | 展开状态对象,键为节点 key,值为展开状态 | | dragdrop | boolean | false | 是否启用拖拽功能 | | dragdropScope | string | undefined | 拖拽作用域,相同作用域的树可以互相拖拽 | | autoUpdate | boolean | false | 同树拖拽时是否自动更新数据源 | | crossTreeAutoUpdate | boolean | false | 🆕 v1.4.0 跨树拖拽时是否自动更新数据源 | | crossTreeDataProvider | CrossTreeDataProvider | undefined | 🆕 v1.4.0 跨树数据提供者,用于获取和更新不同树的数据 | | filter | boolean | false | 是否启用过滤功能 | | filterMode | 'lenient' \| 'strict' | 'lenient' | 过滤模式:宽松模式显示匹配节点的父节点,严格模式只显示匹配节点 | | filterBy | string | 'label' | 过滤字段,指定按哪个字段进行过滤 | | lazy | boolean | false | 是否启用懒加载,适用于大数据量场景 | | loading | boolean | false | 加载状态,显示加载指示器 | | indent | number | 1 | 缩进级别,控制子节点的缩进距离 | | metaKeySelection | boolean | true | 是否支持 Ctrl/Cmd 键多选 |

Tree 组件事件

| 事件 | 参数 | 描述 | |------|------|------| | node-select | TreeNodeSelectEvent | 节点选中时触发 | | node-unselect | TreeNodeUnselectEvent | 节点取消选中时触发 | | node-expand | TreeNodeExpandEvent | 节点展开时触发 | | node-collapse | TreeNodeCollapseEvent | 节点折叠时触发 | | node-focus | TreeNodeFocusEvent | 节点获得焦点时触发 | | node-blur | TreeNodeBlurEvent | 节点失去焦点时触发 | | node-click | TreeNodeClickEvent | 节点点击时触发 | | node-drop | TreeNodeDropEvent | 节点拖拽放置时触发 | | node-drag-start | { originalEvent, node } | 开始拖拽时触发 | | node-drag-end | { originalEvent, node } | 拖拽结束时触发 | | cross-tree-drag-start | CrossTreeDragStartEvent | 跨树拖拽开始时触发 | | cross-tree-drag-enter | CrossTreeDragEnterEvent | 拖拽节点进入目标树时触发 | | cross-tree-drag-over | CrossTreeDragOverEvent | 拖拽节点在目标树上方移动时触发 | | cross-tree-drag-leave | CrossTreeDragLeaveEvent | 拖拽节点离开目标树时触发 | | cross-tree-drop | CrossTreeDropEvent | 跨树拖拽放置时触发 | | cross-tree-drag-end | CrossTreeDragEndEvent | 跨树拖拽结束时触发(无论成功或失败) | | cross-tree-drag-cancel | CrossTreeDragCancelEvent | 跨树拖拽取消时触发(如按 ESC 键) |

TreeNode 接口

interface TreeNode {
  key: string | number          // 节点唯一标识
  label: string                 // 节点显示文本
  data?: any                   // 节点关联数据
  icon?: string | Component    // 节点图标
  children?: TreeNode[]        // 子节点
  leaf?: boolean              // 是否为叶子节点
  expanded?: boolean          // 是否展开
  selectable?: boolean        // 是否可选择
  draggable?: boolean         // 是否可拖拽
  droppable?: boolean         // 是否可作为拖拽目标
  styleClass?: string         // 自定义样式类
  style?: Record<string, any> // 自定义样式
}

CrossTreeDataProvider 接口

🆕 v1.4.0 新增功能

CrossTreeDataProvider 是跨树拖拽自动更新功能的核心接口,它提供了统一的数据访问和更新机制。

interface CrossTreeDataProvider {
  /**
   * 获取指定树的数据
   * @param treeId 树的唯一标识符(通常是组件的 id 属性)
   * @returns 树的数据数组,如果树不存在则返回 null 或 undefined
   */
  getTreeData: (treeId: string) => TreeNode[] | null | undefined
  
  /**
   * 更新指定树的数据
   * @param treeId 树的唯一标识符
   * @param newData 新的树数据
   */
  updateTreeData: (treeId: string, newData: TreeNode[]) => void
}

使用说明

  1. 必须为每个树组件设置唯一的 id 属性
  2. 实现 getTreeData 方法:根据 treeId 返回对应树的数据
  3. 实现 updateTreeData 方法:根据 treeId 更新对应树的数据
  4. 将同一个 CrossTreeDataProvider 实例传递给所有参与跨树拖拽的树组件

错误处理

  • 如果 getTreeData 返回 nullundefined,跨树拖拽将被阻止
  • 确保 updateTreeData 方法能正确处理数据更新,避免响应式丢失
  • 建议在方法中添加适当的错误处理和日志记录

使用示例

1. 基础树形展示

<template>
  <Tree :value="basicData" />
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const basicData = [
  {
    key: '1',
    label: '文档',
    children: [
      { key: '1-1', label: '安装指南.md' },
      { key: '1-2', label: '快速开始.md' }
    ]
  }
]
</script>

2. 多选模式

<template>
  <Tree
    :value="data"
    v-model:selectionKeys="selectedKeys"
    selectionMode="multiple"
    :metaKeySelection="false"
  />
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const selectedKeys = ref({})
</script>

3. 复选框选择

<template>
  <Tree
    :value="data"
    v-model:selectionKeys="selectedKeys"
    selectionMode="checkbox"
  />
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'
</script>

4. 拖拽功能

自动更新模式(推荐)

<template>
  <Tree
    :value="data"
    :autoUpdate="true"
    dragdropScope="demo"
    @node-drop="onNodeDrop"
  />
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const data = ref([...]) // 你的树形数据

const onNodeDrop = (event) => {
  // 自动更新模式下,数据会自动更新,只需要接受拖拽
  event.accept()
  console.log('拖拽完成,数据已自动更新')
}
</script>

手动处理模式

<template>
  <Tree
    :value="data"
    :autoUpdate="false"
    dragdropScope="demo"
    @node-drop="onNodeDrop"
  />
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const data = ref([...]) // 你的树形数据

const onNodeDrop = (event) => {
  // 手动处理拖拽逻辑
  const { dragNode, dropNode, dropIndex } = event
  
  // 自定义拖拽处理逻辑
  if (dropNode) {
    // 拖拽到节点上
    if (!dropNode.children) dropNode.children = []
    dropNode.children.push(dragNode)
  } else {
    // 拖拽到根级别
    data.value.splice(dropIndex, 0, dragNode)
  }
  
  event.accept()
}
</script>

5. 跨树拖拽自动更新

推荐:自动更新模式

<template>
  <div class="flex gap-4">
    <!-- 源树 -->
    <div class="w-1/2">
      <h3>源树</h3>
      <Tree
        id="source-tree"
        :value="sourceData"
        :dragdrop="true"
        dragdropScope="cross-tree"
        :crossTreeAutoUpdate="true"
        :crossTreeDataProvider="crossTreeDataProvider"
        @cross-tree-drop="onCrossTreeDrop"
      />
    </div>
    
    <!-- 目标树 -->
    <div class="w-1/2">
      <h3>目标树</h3>
      <Tree
        id="target-tree"
        :value="targetData"
        :dragdrop="true"
        dragdropScope="cross-tree"
        :crossTreeAutoUpdate="true"
        :crossTreeDataProvider="crossTreeDataProvider"
        @cross-tree-drop="onCrossTreeDrop"
      />
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const sourceData = ref([
  {
    key: 'source-1',
    label: '源节点 1',
    children: [
      { key: 'source-1-1', label: '源子节点 1-1' },
      { key: 'source-1-2', label: '源子节点 1-2' }
    ]
  }
])

const targetData = ref([
  {
    key: 'target-1',
    label: '目标节点 1',
    children: []
  }
])

// 跨树数据提供者
const crossTreeDataProvider = {
  getTreeData: (treeId) => {
    if (treeId === 'source-tree') return sourceData.value
    if (treeId === 'target-tree') return targetData.value
    return null
  },
  
  updateTreeData: (treeId, newData) => {
    if (treeId === 'source-tree') {
      sourceData.value = newData
    } else if (treeId === 'target-tree') {
      targetData.value = newData
    }
  }
}

// 可选:监听跨树拖拽事件
const onCrossTreeDrop = (event) => {
  console.log('跨树拖拽完成:', {
    sourceTreeId: event.sourceTreeId,
    targetTreeId: event.targetTreeId,
    dragNode: event.dragNode,
    dropNode: event.dropNode,
    dropIndex: event.dropIndex
  })
}
</script>

6. 跨树拖拽手动模式

基础跨树拖拽

<template>
  <div class="flex gap-4">
    <Tree
      ref="sourceTree"
      :value="sourceData"
      dragdropScope="cross-tree"
      @node-drop="onCrossTreeDrop"
    />
    <Tree
      ref="targetTree"
      :value="targetData"
      dragdropScope="cross-tree"
      @node-drop="onCrossTreeDrop"
    />
  </div>
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const onCrossTreeDrop = (event) => {
  // 处理跨树拖拽
  if (event.isCrossTree) {
    // 跨树拖拽逻辑
    event.accept()
  }
}
</script>

完整跨树拖拽事件监听

<template>
  <div class="flex gap-4">
    <Tree
      id="tree1"
      :value="sourceData"
      dragdropScope="cross-tree"
      @node-drop="onCrossTreeDrop"
      @cross-tree-drag-start="onCrossTreeDragStart"
      @cross-tree-drag-enter="onCrossTreeDragEnter"
      @cross-tree-drag-over="onCrossTreeDragOver"
      @cross-tree-drag-leave="onCrossTreeDragLeave"
      @cross-tree-drop="onCrossTreeDropEvent"
      @cross-tree-drag-end="onCrossTreeDragEnd"
      @cross-tree-drag-cancel="onCrossTreeDragCancel"
    />
    <Tree
      id="tree2"
      :value="targetData"
      dragdropScope="cross-tree"
      @node-drop="onCrossTreeDrop"
      @cross-tree-drag-start="onCrossTreeDragStart"
      @cross-tree-drag-enter="onCrossTreeDragEnter"
      @cross-tree-drag-over="onCrossTreeDragOver"
      @cross-tree-drag-leave="onCrossTreeDragLeave"
      @cross-tree-drop="onCrossTreeDropEvent"
      @cross-tree-drag-end="onCrossTreeDragEnd"
      @cross-tree-drag-cancel="onCrossTreeDragCancel"
    />
  </div>
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

// 跨树拖拽开始
const onCrossTreeDragStart = (event) => {
  console.log('跨树拖拽开始:', {
    sourceTreeId: event.sourceTreeId,
    dragNode: event.dragNode,
    isCrossTree: event.isCrossTree,
    timestamp: event.timestamp
  })
}

// 拖拽节点进入目标树
const onCrossTreeDragEnter = (event) => {
  console.log('进入目标树:', {
    sourceTreeId: event.sourceTreeId,
    targetTreeId: event.targetTreeId,
    dragNode: event.dragNode
  })
}

// 拖拽节点在目标树上方移动(频繁触发)
const onCrossTreeDragOver = (event) => {
  // 由于频繁触发,通常只做必要的处理
  console.log('在目标树上方移动')
}

// 拖拽节点离开目标树
const onCrossTreeDragLeave = (event) => {
  console.log('离开目标树:', {
    targetTreeId: event.targetTreeId,
    dragNode: event.dragNode
  })
}

// 跨树拖拽放置
const onCrossTreeDropEvent = (event) => {
  console.log('跨树拖拽放置:', {
    sourceTreeId: event.sourceTreeId,
    targetTreeId: event.targetTreeId,
    dragNode: event.dragNode,
    dropNode: event.dropNode,
    dropPosition: event.dropPosition
  })
}

// 跨树拖拽结束
const onCrossTreeDragEnd = (event) => {
  console.log('跨树拖拽结束:', {
    success: event.success,
    sourceTreeId: event.sourceTreeId,
    targetTreeId: event.targetTreeId
  })
}

// 跨树拖拽取消(如按 ESC 键)
const onCrossTreeDragCancel = (event) => {
  console.log('跨树拖拽取消:', {
    sourceTreeId: event.sourceTreeId,
    dragNode: event.dragNode
  })
}

// 传统的 node-drop 事件处理
const onCrossTreeDrop = (event) => {
  if (event.isCrossTree) {
    event.accept()
  }
}
</script>

跨树拖拽自动更新

crossTreeAutoUpdate 参数控制跨树拖拽时是否自动更新数据源。v1.3.0 版本完善了跨树拖拽的数据同步机制,确保在两种模式下都能正确更新数据:

  • 自动更新模式 (crossTreeAutoUpdate: true):拖拽操作会自动调用 accept() 方法并同步更新源树和目标树的数据
  • 手动确认模式 (crossTreeAutoUpdate: false):需要手动调用 accept()reject() 方法,确认后才会更新数据
<template>
  <div class="flex gap-4">
    <!-- 自动更新模式 -->
    <Tree
      id="auto-tree1"
      :value="autoData1"
      :crossTreeAutoUpdate="true"
      :dragdrop="true"
      dragdropScope="auto-cross-tree"
      @cross-tree-drop="onAutoUpdateDrop"
    />
    <Tree
      id="auto-tree2"
      :value="autoData2"
      :crossTreeAutoUpdate="true"
      :dragdrop="true"
      dragdropScope="auto-cross-tree"
      @cross-tree-drop="onAutoUpdateDrop"
    />
    
    <!-- 手动控制模式 -->
    <Tree
      id="manual-tree1"
      :value="manualData1"
      :crossTreeAutoUpdate="false"
      :dragdrop="true"
      dragdropScope="manual-cross-tree"
      @cross-tree-drop="onManualControlDrop"
    />
    <Tree
      id="manual-tree2"
      :value="manualData2"
      :crossTreeAutoUpdate="false"
      :dragdrop="true"
      dragdropScope="manual-cross-tree"
      @cross-tree-drop="onManualControlDrop"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const autoData1 = ref([...]) // 自动更新模式的源树数据
const autoData2 = ref([...]) // 自动更新模式的目标树数据
const manualData1 = ref([...]) // 手动控制模式的源树数据
const manualData2 = ref([...]) // 手动控制模式的目标树数据

// 自动更新模式:拖拽会自动完成数据同步
const onAutoUpdateDrop = (event) => {
  console.log('自动更新拖拽:', event)
  // v1.3.0 版本已完善数据同步机制,无需手动处理数据更新
  // 组件会自动调用 accept() 并更新源树和目标树的数据
}

// 手动控制模式:需要手动决定是否接受拖拽
const onManualControlDrop = (event) => {
  console.log('手动控制拖拽:', event)
  
  // 根据业务逻辑决定是否接受拖拽
  const shouldAccept = validateDragOperation(event)
  
  if (shouldAccept) {
    event.accept() // 接受拖拽,自动更新源树和目标树数据
  } else {
    event.reject() // 拒绝拖拽,不更新数据
  }
}

const validateDragOperation = (event) => {
  // 自定义验证逻辑
  return event.dragNode.label !== '禁止拖拽的节点'
}
</script>

使用场景:

  • 自动更新模式 (crossTreeAutoUpdate: true):适用于简单的拖拽操作,无需复杂验证
  • 手动控制模式 (crossTreeAutoUpdate: false):适用于需要验证、确认或异步处理的拖拽操作

注意事项:

  1. crossTreeAutoUpdate 只影响跨树拖拽,不影响同树内的拖拽操作
  2. 手动控制模式下,必须调用 accept()reject() 方法,否则拖拽状态不会清理
  3. 可以与 autoUpdate 参数配合使用,分别控制同树和跨树的拖拽行为

7. 节点过滤

<template>
  <Tree
    :value="data"
    :filter="true"
    filterBy="label"
    filterPlaceholder="搜索节点..."
  />
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'
</script>

8. 懒加载

<template>
  <Tree
    :value="data"
    :lazy="true"
    @node-load="onNodeLoad"
  />
</template>

<script setup>
import { Tree } from 'vue3-super-tree'
import 'vue3-super-tree/style.css'

const onNodeLoad = async (event) => {
  // 异步加载子节点
  const children = await fetchChildren(event.node.key)
  event.node.children = children
}
</script>

键盘操作

| 按键 | 功能 | |------|------| | ↑/↓ | 上下导航 | | ←/→ | 展开/折叠节点 | | Enter | 选择节点 | | Space | 切换复选框状态 | | Home | 跳转到第一个节点 | | End | 跳转到最后一个节点 | | Ctrl/Cmd + A | 全选(多选模式) |

样式定制

导入样式

// 导入默认样式
import 'vue3-super-tree/style.css'

原生焦点样式

组件使用浏览器原生的 :focus 伪类来管理焦点样式,提供更好的性能和无障碍访问体验:

/* 组件内置的焦点样式 */
.tree-node:focus {
  outline: 2px solid #3b82f6;
  outline-offset: -2px;
  background-color: #eff6ff;
}

/* 自定义焦点样式 */
.tree-node:focus {
  outline: 2px solid #10b981;
  background-color: #ecfdf5;
  border-radius: 0.375rem;
}

主题变量

组件支持通过 CSS 变量进行主题定制:

:root {
  --tree-node-padding: 0.5rem;
  --tree-node-border-radius: 0.375rem;
  --tree-selected-bg: #3b82f6;
  --tree-selected-color: white;
  --tree-focus-bg: #eff6ff;
  --tree-focus-color: #1e40af;
  --tree-focus-outline: #3b82f6;
}

自定义样式类

<Tree
  :value="data"
  class="custom-tree"
  :selectedBackgroundColor="#10b981"
  :selectedTextColor="white"
  :focusBackgroundColor="#ecfdf5"
  :focusTextColor="#059669"
/>

相关链接

  • npm 包: https://www.npmjs.com/package/vue3-super-tree
  • GitHub 仓库: https://github.com/zuoanCo/vue3-super-tree
  • 在线演示: https://zuoanCo.github.io/vue3-super-tree
  • API 文档: https://github.com/zuoanCo/vue3-super-tree#api-文档
  • 问题反馈: https://github.com/zuoanCo/vue3-super-tree/issues

技术栈

  • Vue 3.4+ - 渐进式 JavaScript 框架
  • TypeScript - 类型安全的 JavaScript 超集
  • Vite - 快速的前端构建工具
  • Tailwind CSS - 实用优先的 CSS 框架
  • Lucide Icons - 美观的图标库

性能优化

生产构建优化

组件在生产环境下自动进行以下优化:

  • 调试日志移除 - 自动移除所有 console.log 调试信息
  • 代码压缩 - 使用 Terser 进行代码压缩和混淆
  • Tree Shaking - 移除未使用的代码,减小包体积
  • 原生焦点管理 - 使用浏览器原生 :focus 伪类,减少 JavaScript 开销

运行时性能

  • 虚拟滚动 - 大数据量时自动启用虚拟滚动
  • 智能更新 - 只更新变化的节点,避免全量重渲染
  • 内存优化 - 及时清理事件监听器和引用

项目结构

vue3-super-tree/
├── src/
│   ├── components/          # 组件目录
│   │   ├── Tree.vue        # 主树组件
│   │   ├── TreeNode.vue    # 树节点组件
│   │   └── index.ts        # 组件导出
│   ├── lib/                # 核心库
│   │   ├── types.ts        # TypeScript 类型定义
│   │   ├── utils.ts        # 工具函数
│   │   ├── themes.ts       # 主题配置
│   │   └── index.ts        # 库导出
│   ├── composables/        # 组合式函数
│   │   ├── useDragDrop.ts  # 拖拽功能
│   │   ├── useSelection.ts # 选择功能
│   │   ├── useFilter.ts    # 过滤功能
│   │   └── index.ts        # 组合函数导出
│   └── style.css           # 样式文件
├── dist/                   # 构建输出
├── package.json           # 包配置
├── vite.lib.config.ts     # Vite 库构建配置
└── README.md              # 项目文档

🔧 故障排除

常见问题

1. 构建错误

问题: TypeScript 构建失败,出现类型错误

error TS2742: The inferred type of 'xxx' cannot be named without a reference to '@vue/shared'

解决方案:

  • 确保使用的是 v1.4.0 或更高版本,该版本已修复所有构建错误
  • 检查 TypeScript 版本是否兼容(推荐 4.9+)
  • 清理缓存:rm -rf node_modules/.cache && pnpm install

2. 跨树拖拽不工作

问题: 跨树拖拽功能无法正常工作

解决方案:

  • 确保所有参与跨树拖拽的树组件都设置了相同的 dragdropScope
  • 检查是否为每个树组件设置了唯一的 id 属性
  • 确保 CrossTreeDataProvider 正确实现了 getTreeDataupdateTreeData 方法
  • 检查控制台是否有错误信息

3. 自动更新不生效

问题: 设置了 autoUpdatecrossTreeAutoUpdate 但数据没有自动更新

解决方案:

  • 确保在拖拽事件处理器中调用了 event.accept()
  • 检查数据是否为响应式对象(使用 refreactive
  • 对于跨树拖拽,确保 CrossTreeDataProviderupdateTreeData 方法正确更新了响应式数据

4. 性能问题

问题: 大数据量时性能较差

解决方案:

  • 启用懒加载:设置 lazy="true"
  • 使用虚拟滚动(如果数据量特别大)
  • 避免在节点模板中使用复杂的计算
  • 考虑分页或分批加载数据

5. 样式问题

问题: 样式显示不正确

解决方案:

  • 确保导入了样式文件:import 'vue3-super-tree/style.css'
  • 检查 CSS 优先级,避免样式被覆盖
  • 使用浏览器开发者工具检查样式应用情况

调试建议

1. 开启调试模式

在开发环境中,组件会输出详细的调试信息:

// 在浏览器控制台中查看调试信息
console.log('Vue3 Super Tree Debug Mode: ON')

2. 检查事件流

监听所有相关事件来调试问题:

<template>
  <Tree
    @node-drop="onNodeDrop"
    @cross-tree-drop="onCrossTreeDrop"
    @cross-tree-drag-start="onDragStart"
    @cross-tree-drag-end="onDragEnd"
  />
</template>

<script setup>
const onNodeDrop = (event) => {
  console.log('Node drop:', event)
}

const onCrossTreeDrop = (event) => {
  console.log('Cross tree drop:', event)
}

const onDragStart = (event) => {
  console.log('Drag start:', event)
}

const onDragEnd = (event) => {
  console.log('Drag end:', event)
}
</script>

3. 数据结构验证

确保树形数据结构正确:

// 正确的数据结构
const treeData = [
  {
    key: 'unique-key',      // 必须:唯一标识
    label: 'Node Label',    // 必须:显示文本
    children: [             // 可选:子节点数组
      {
        key: 'child-key',
        label: 'Child Node'
      }
    ]
  }
]

性能优化建议

1. 大数据量优化

<template>
  <Tree
    :value="data"
    :lazy="true"
    :loading="loading"
    @node-expand="loadChildren"
  />
</template>

<script setup>
const loadChildren = async (node) => {
  loading.value = true
  try {
    const children = await fetchChildren(node.key)
    node.children = children
  } finally {
    loading.value = false
  }
}
</script>

2. 减少重渲染

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

// 使用 shallowRef 减少深度响应式开销
const treeData = shallowRef([])

// 使用 computed 缓存计算结果
const filteredData = computed(() => {
  return filterTreeData(treeData.value, searchTerm.value)
})
</script>

3. 事件处理优化

<script setup>
// 使用防抖避免频繁触发
import { debounce } from 'lodash-es'

const handleSearch = debounce((searchTerm) => {
  // 搜索逻辑
}, 300)
</script>

版本升级指南

从 v1.3.x 升级到 v1.4.0

  1. 新增功能

    • 跨树拖拽自动更新功能
    • CrossTreeDataProvider 接口
    • 全局状态管理
  2. 破坏性变更

    • 无破坏性变更,完全向后兼容
  3. 推荐更新

    • 使用新的跨树拖拽自动更新功能替代手动处理
    • 更新 TypeScript 类型定义

🤝 贡献指南

欢迎贡献代码!vue3-super-tree 是一个开源 npm 包,我们欢迎社区的贡献。

开发环境设置

  1. 克隆项目
git clone https://github.com/zuoanCo/vue3-super-tree.git
cd vue3-super-tree
  1. 安装依赖
pnpm install
  1. 启动开发服务器
pnpm run dev
  1. 构建库文件
pnpm run build:lib

贡献流程

  1. Fork 项目
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启 Pull Request

开发规范

  • 使用 TypeScript 编写代码
  • 遵循 Vue 3 Composition API 最佳实践
  • 添加适当的类型注解
  • 编写清晰的注释
  • 确保代码通过 ESLint 检查
  • 添加相应的测试用例

代码规范

项目使用 ESLint 进行代码检查:

# 检查代码
pnpm run lint

# 自动修复
pnpm run lint:fix

许可证

本项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。

致谢

📊 包信息

版本信息

  • 当前版本: v1.4.0 🆕
  • 发布状态: 生产就绪 ✅
  • 构建状态: 通过 (44个错误已修复) ✅

技术规格

  • 包大小: ~220KB (生产优化后)
  • 支持的 Vue 版本: 3.4+
  • Node.js 版本: 16.0+
  • TypeScript 支持: 100% 类型安全 ✅
  • Tree Shaking: 完全支持 ✅
  • SSR 支持: 服务端渲染友好 ✅

功能特性

  • 原生焦点管理: 基于浏览器原生 :focus 伪类 ✅
  • 自动拖拽更新: 同树拖拽自动更新 ✅
  • 跨树拖拽自动更新: v1.4.0 新增功能 🆕
  • 全局状态管理: useCrossTreeDragState ✅
  • 错误处理: 完整的错误边界和恢复机制 ✅
  • 性能优化: 生产构建自动优化 ✅

构建产物

  • ES 模块: dist/index.es.js
  • UMD 版本: dist/index.umd.js
  • 类型定义: dist/index.d.ts
  • 样式文件: dist/style.css

如果这个项目对你有帮助,请给它一个 ⭐️!

Star History Chart