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

@hjxz/pharos-tree

v0.0.1

Published

hjxz 树组件

Readme

PharosTree 树组件

基于 Vue 3 和 Ant Design Vue 的树组件,支持无限级展开收起、拖拽、多选、联动等功能。

功能特性

  • ✅ 可无限级展开收起子节点
  • ✅ 可配置字符 fieldNames
  • ✅ 树节点可以拖拽
  • ✅ 支持静态数据和 API 请求两种数据导入方式
  • ✅ 数据加载模式,加载中显示 Spinner 动画
  • ✅ 可配置是否多选,支持全选、半选中、未选中状态
  • ✅ 可配置联动规则,支持父子级节点是否联动
  • ✅ 支持虚拟滚动,优化大量节点时的性能

安装

npm install @hjxz/pharos-tree
# 或
pnpm add @hjxz/pharos-tree

基础用法

静态数据

<template>
  <PharosTree :tree-data="treeData" />
</template>

<script setup lang="ts">
import { PharosTree } from '@hjxz/pharos-tree'

const treeData = [
  {
    key: '1',
    label: '节点 1',
    children: [
      {
        key: '1-1',
        label: '节点 1-1',
        children: [
          { key: '1-1-1', label: '节点 1-1-1' }
        ]
      }
    ]
  }
]
</script>

API 数据

<template>
  <PharosTree :api="fetchTreeData" />
</template>

<script setup lang="ts">
import { PharosTree } from '@hjxz/pharos-tree'

const fetchTreeData = async (params?: { parentId?: string }) => {
  // 请求 API
  const response = await fetch(`/api/tree?parentId=${params?.parentId || ''}`)
  return response.json()
}
</script>

配置 fieldNames

<template>
  <PharosTree 
    :tree-data="treeData"
    :field-names="{
      key: 'id',
      label: 'name',
      children: 'childList'
    }"
  />
</template>

多选模式

<template>
  <PharosTree 
    :tree-data="treeData"
    checkable
    :check-strictly="false"
    v-model:checked-keys="checkedKeys"
    @check="handleCheck"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'

const checkedKeys = ref<string[]>([])

const handleCheck = (keys: string[], info: any) => {
  console.log('选中的节点:', keys)
  console.log('半选中的节点:', info.halfCheckedKeys)
}
</script>

拖拽功能

<template>
  <PharosTree 
    :tree-data="treeData"
    draggable
    @dragstart="handleDragStart"
    @drop="handleDrop"
  />
</template>

<script setup lang="ts">
const handleDragStart = (info: any) => {
  console.log('开始拖拽:', info.node)
}

const handleDrop = (info: any) => {
  console.log('放置节点:', info.node)
  console.log('拖拽的节点:', info.dragNode)
  // 在这里处理节点移动逻辑
}
</script>

虚拟滚动

<template>
  <PharosTree 
    :tree-data="treeData"
    :virtual-scroll="true"
    :visible-count="15"
    :list-height="400"
    :item-height="32"
  />
</template>

<script setup lang="ts">
import { PharosTree } from '@hjxz/pharos-tree'

// 虚拟滚动适用于节点数量较多的场景,可以显著提升性能
// visibleCount: 控制在视口中同时渲染的节点数量
// listHeight: 设置树容器的固定高度,超过此高度时显示滚动条
// itemHeight: 每个节点的高度,需要与实际节点高度一致
</script>

API

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | treeData | 树形数据 | TreeNode[] | [] | | api | 异步获取树数据的函数 | (params?: { parentId?: string }) => Promise<TreeNode[]> | - | | indent | 缩进距离(px) | number | 16 | | disabled | 是否禁用 | boolean | false | | checkable | 是否显示复选框 | boolean | false | | multiple | 是否多选 | boolean | false | | fieldNames | 字段映射配置 | TreeFieldNames | - | | draggable | 是否可拖拽 | boolean | false | | checkStrictly | 是否启用父子节点关联。false 表示父子节点关联,true 表示不关联 | boolean | false | | defaultExpandedKeys | 默认展开的节点 key | string[] | [] | | defaultCheckedKeys | 默认选中的节点 key | string[] | [] | | expandedKeys | 受控的展开节点 key(v-model:expandedKeys) | string[] | - | | checkedKeys | 受控的选中节点 key(v-model:checkedKeys) | string[] | - | | itemHeight | 节点高度(px) | number | 32 | | noDataText | 无数据提示文本 | string | '暂无数据' | | virtualScroll | 是否启用虚拟滚动 | boolean | false | | visibleCount | 可见节点数量(仅在启用虚拟滚动时有效) | number | 10 | | listHeight | 列表高度(px,仅在启用虚拟滚动时有效) | number | 256 |

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | update:checkedKeys | 选中节点变化时触发 | (keys: string[]) | | update:expandedKeys | 展开节点变化时触发 | (keys: string[]) | | check | 点击复选框时触发 | (keys: string[], info: { checked: boolean; node: TreeNodeInternal; checkedNodes: TreeNodeInternal[]; halfCheckedKeys?: string[] }) | | expand | 展开/收起节点时触发 | (keys: string[], info: { expanded: boolean; node: TreeNodeInternal }) | | select | 选择节点时触发(单选模式) | (keys: string[], info: { node: TreeNodeInternal; selected: boolean }) | | dragstart | 开始拖拽时触发 | (info: { event: DragEvent; node: TreeNodeInternal }) | | dragenter | 拖拽进入节点时触发 | (info: { event: DragEvent; node: TreeNodeInternal; expanded: boolean }) | | dragover | 拖拽悬停在节点上时触发 | (info: { event: DragEvent; node: TreeNodeInternal }) | | dragleave | 拖拽离开节点时触发 | (info: { event: DragEvent; node: TreeNodeInternal }) | | drop | 放置节点时触发 | (info: { event: DragEvent; node: TreeNodeInternal; dragNode: TreeNodeInternal }) | | dragend | 拖拽结束时触发 | (info: { event: DragEvent; node: TreeNodeInternal }) | | load | 节点懒加载完成时触发 | (node: TreeNodeInternal) |

TreeFieldNames

| 字段 | 说明 | 类型 | 默认值 | |------|------|------|--------| | key | 唯一标识字段名 | string | 'key' | | label | 显示文本字段名 | string | 'label' | | value | 值字段名 | string | 'key' | | children | 子节点字段名 | string | 'children' | | disabled | 禁用状态字段名 | string | 'disabled' | | isLeaf | 是否叶子节点字段名 | string | 'isLeaf' | | extra | 额外数据字段名 | string | 'extra' |

TreeNode

| 字段 | 说明 | 类型 | 必填 | |------|------|------|------| | key | 唯一标识 | string | ✅ | | label | 显示文本 | string | ✅ | | children | 子节点 | TreeNode[] | - | | disabled | 是否禁用 | boolean | - | | isLeaf | 是否叶子节点 | boolean | - | | value | 值 | string | - | | extra | 额外数据 | any | - |

示例

完整示例

<template>
  <div>
    <PharosTree
      :tree-data="treeData"
      :field-names="fieldNames"
      checkable
      :check-strictly="false"
      draggable
      :virtual-scroll="true"
      :visible-count="15"
      :list-height="400"
      :default-expanded-keys="['1']"
      :default-checked-keys="['1-1']"
      v-model:checked-keys="checkedKeys"
      v-model:expanded-keys="expandedKeys"
      @check="handleCheck"
      @expand="handleExpand"
      @drop="handleDrop"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { PharosTree } from '@hjxz/pharos-tree'

const treeData = [
  {
    key: '1',
    label: '父节点 1',
    children: [
      { key: '1-1', label: '子节点 1-1' },
      { key: '1-2', label: '子节点 1-2' }
    ]
  },
  {
    key: '2',
    label: '父节点 2',
    children: [
      { key: '2-1', label: '子节点 2-1' },
      { key: '2-2', label: '子节点 2-2' }
    ]
  }
]

const fieldNames = {
  key: 'key',
  label: 'label',
  children: 'children'
}

const checkedKeys = ref<string[]>([])
const expandedKeys = ref<string[]>([])

const handleCheck = (keys: string[], info: any) => {
  console.log('选中的节点:', keys)
  console.log('半选中的节点:', info.halfCheckedKeys)
}

const handleExpand = (keys: string[], info: any) => {
  console.log('展开的节点:', keys)
}

const handleDrop = (info: any) => {
  console.log('放置节点:', info.node)
  console.log('拖拽的节点:', info.dragNode)
}
</script>

注意事项

  1. 当使用 API 方式加载数据时,组件会在节点展开时自动调用 API 加载子节点(懒加载)
  2. 拖拽功能中,不允许将节点拖拽到自己的子节点中
  3. 半选中状态只在 checkStrictly: false(父子节点关联)时生效
  4. checkStrictly: true 时,父子节点的选中状态互不影响
  5. 虚拟滚动
    • 当节点数量较多(建议超过 100 个可见节点)时,建议启用虚拟滚动以提升性能
    • itemHeight 需要与实际节点高度一致,否则可能出现滚动位置不准确的问题
    • visibleCount 建议设置为略大于可视区域内能显示的节点数量,一般设置为 Math.ceil(listHeight / itemHeight) + 2
    • 虚拟滚动模式下,只渲染可见区域的节点,滚动时会动态加载和卸载节点
    • 虚拟滚动与拖拽功能完全兼容,可以同时使用

License

MIT