@wsh704/vue3-tree-org-department
v1.0.2
Published
基于 `vue3-tree-org` 扩展的 Vue 3 组织架构图组件包。当前包保留原有 `<vue3-tree-org>` 的基础组织树能力,并提供 `<department-tree>` 增强用法:在原组织树能力之上多传一个 `bottomNode`,自动生成最后一行底部汇总和匹配连线。
Maintainers
Readme
@wsh704/vue3-tree-org-department 使用方法
基于 vue3-tree-org 扩展的 Vue 3 组织架构图组件包。当前包保留原有 <vue3-tree-org> 的基础组织树能力,并提供 <department-tree> 增强用法:在原组织树能力之上多传一个 bottomNode,自动生成最后一行底部汇总和匹配连线。
当前源码版本:
@wsh704/[email protected]当前公网 npm 可查版本:
@wsh704/[email protected]说明:1.0.2 已在本地源码和 tarball 中完成构建验证,并已安装到 vue3-demo 验证通过;该版本修复了部门 tree 底部汇总框在多层节点高度不一致时可能和节点重叠的问题。公网 npm 当前仍是 1.0.1,发布 1.0.2 需要 npm 发布 OTP,或带 Bypass 2FA 权限的 granular access token。
功能概览
- 支持普通组织树展示。
- 支持组织树拖拽、缩放、居中、横向布局。
- 支持节点展开/收起、默认展开层级、指定展开节点。
- 支持默认右键菜单:复制文本、新增节点、编辑节点、删除节点。
- 支持自定义右键菜单。
- 支持自定义节点插槽、自定义展开按钮插槽。
- 支持搜索过滤。
- 支持懒加载子节点。
- 支持组织树注释连线,注释可以连接一个或多个节点。
- 支持右键新增、选择、编辑、删除注释。
- 新增
DepartmentTree/<department-tree>部门树增强能力:- 在原组织树所有基础能力之上增加
bottomNode汇总。 - 支持原
<vue3-tree-org>的属性、事件、方法和插槽继续使用。 - 推荐接收
{ root, bottomNode }业务数据,也支持在根节点数据上直接多放一个bottomNode。 root是原多级组织树数据。bottomNode是组织树之外的底部汇总节点。- 只在组织树最后一级叶子节点按姓名匹配汇总,不跨级匹配。
title和position固定展示,只有姓名可以右键编辑。- 右键某个组织节点或底部分组后,该节点/分组内所有姓名都可以单独编辑。
- 在原组织树所有基础能力之上增加
安装
npm install @wsh704/vue3-tree-org-department --save也可以使用 yarn 或 pnpm:
yarn add @wsh704/vue3-tree-org-department
pnpm add @wsh704/vue3-tree-org-department如果需要明确从 npm 公网安装:
npm install @wsh704/vue3-tree-org-department --registry=https://registry.npmjs.org/全局引入
在 main.js 或 main.ts 中引入:
import { createApp } from 'vue'
import App from './App.vue'
import treeOrg from '@wsh704/vue3-tree-org-department'
import '@wsh704/vue3-tree-org-department/lib/vue3-tree-org.css'
const app = createApp(App)
app.use(treeOrg)
app.mount('#app')全局引入后可以直接在模板中使用:
<template>
<vue3-tree-org :data="treeData" />
<department-tree :data="departmentData" />
</template>局部引入
如果不想全局注册,也可以局部引入组件。
<template>
<vue3-tree-org :data="treeData" />
<department-tree :data="departmentData" />
</template>
<script setup>
import { Vue3TreeOrg, DepartmentTree } from '@wsh704/vue3-tree-org-department'
import '@wsh704/vue3-tree-org-department/lib/vue3-tree-org.css'
const treeData = {
id: 'root',
pid: '',
label: '安全生产领导小组',
children: []
}
const departmentData = {
root: {
title: '安全生产领导小组',
type: 1,
members: [],
children: []
},
bottomNode: {
title: '驾驶员、押运员、装卸管理人员',
members: [],
children: []
}
}
</script>在 <script setup> 中,导入的 Vue3TreeOrg 和 DepartmentTree 会自动可用于模板,模板中可以写 <Vue3TreeOrg> / <DepartmentTree>,也可以写 kebab-case 的 <vue3-tree-org> / <department-tree>。
普通组织树基础用法
普通组织树使用 <vue3-tree-org>。
<template>
<div class="tree-page">
<vue3-tree-org
:data="data"
:props="treeProps"
:center="true"
:collapsable="true"
:default-expand-level="3"
:tool-bar="treeTools"
:draggable="true"
:scalable="true"
:node-draggable="true"
@on-node-click="handleNodeClick"
@on-contextmenu="handleContextmenu"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const treeProps = {
id: 'id',
pid: 'pid',
label: 'label',
children: 'children',
expand: 'expand'
}
const treeTools = {
scale: true,
restore: true,
expand: true,
zoom: true,
fullscreen: true
}
const data = ref({
id: 'root',
pid: '',
label: '安全生产领导小组',
children: [
{
id: 'dispatch',
pid: 'root',
label: '综合调度部',
children: [
{ id: 'waybill', pid: 'dispatch', label: '运单管理员' },
{ id: 'finance', pid: 'dispatch', label: '财务人员' }
]
},
{
id: 'safety',
pid: 'root',
label: '安全部',
children: [
{ id: 'inspector', pid: 'safety', label: '专职安全员' },
{ id: 'monitor', pid: 'safety', label: '专职监控人员' }
]
}
]
})
function handleNodeClick(event, data, node) {
console.log('点击节点:', data, node)
}
function handleContextmenu(payload) {
console.log('右键命令:', payload.command, payload.data)
}
</script>
<style scoped>
.tree-page {
height: 720px;
background: #fff;
}
</style>普通组织树数据默认字段:
| 字段 | 说明 |
| --- | --- |
| id | 节点唯一标识。需要新增、删除、编辑、拖拽时必须有。 |
| pid | 父级节点标识。需要新增、删除、编辑、拖拽时必须有。 |
| label | 节点显示文本。 |
| children | 子节点数组。 |
| expand | 是否展开。 |
| disabled | 当前节点是否禁止编辑。 |
| className | 节点自定义 class。 |
| style | 节点自定义样式。 |
| noDragging | 当前节点是否禁止拖拽画布。 |
如果你的业务字段不是这些名称,可以通过 props 映射:
<vue3-tree-org
:data="data"
:props="{
id: 'deptId',
pid: 'parentId',
label: 'deptName',
children: 'childList',
expand: 'opened'
}"
/>普通组织树自定义节点
使用默认插槽自定义节点内容:
<vue3-tree-org :data="data">
<template #default="{ node }">
<div class="custom-node">
<strong>{{ node.label }}</strong>
<span>{{ node.$$data.duty }}</span>
</div>
</template>
</vue3-tree-org>node 是组件内部节点对象,常用字段:
| 字段 | 说明 |
| --- | --- |
| node.id | 节点 id。 |
| node.label | 节点显示文本。 |
| node.pid | 父节点 id。 |
| node.expand | 是否展开。 |
| node.$$data | 原始业务节点数据。 |
| node.$$level | 当前节点层级。 |
普通组织树自定义展开按钮
<vue3-tree-org :data="data" :collapsable="true">
<template #expand="{ node }">
<span>{{ node.expand ? '-' : '+' }}</span>
</template>
</vue3-tree-org>默认右键菜单
默认右键菜单包含:
复制文本新增节点编辑节点删除节点
<vue3-tree-org
:data="data"
:disabled="false"
@on-contextmenu="handleContextmenu"
@on-node-focus="handleNodeFocus"
@on-node-blur="handleNodeBlur"
@on-node-delete="handleNodeDelete"
/>function handleContextmenu(payload) {
// payload.command: copy / add / edit / delete
// payload.node: 内部节点
// payload.data: 原始业务节点
console.log(payload.command, payload.data)
}
function handleNodeFocus(event, data, node) {
console.log('进入编辑:', data)
}
function handleNodeBlur(event, data, node) {
console.log('结束编辑:', data)
}
function handleNodeDelete(data) {
console.log('删除节点:', data)
}注意:
- 默认新增、编辑、删除依赖节点的
id和pid。 - 根节点不允许默认删除。
- 如果设置
disabled = true,默认新增、编辑、删除不可用。 - 单个节点也可以通过节点数据上的
disabled: true禁止编辑。
自定义右键菜单
<vue3-tree-org
:data="data"
:define-menus="menus"
@on-contextmenu="handleMenu"
/>const menus = [
{ name: '标记已检查', command: 'mark-checked' },
{ name: '记录节点名称', command: 'record-label' }
]
function handleMenu(payload) {
if (payload.command === 'mark-checked') {
payload.data.checked = true
}
if (payload.command === 'record-label') {
console.log(payload.data.label)
}
}define-menus 也可以是函数:
function menus(event, node) {
if (node.$$root) {
return [{ name: '根节点操作', command: 'root-action' }]
}
return [{ name: '普通节点操作', command: 'node-action' }]
}搜索过滤
先给组件设置 filter-node-method,再通过组件实例调用 filter(value)。
<template>
<input v-model="keyword" @input="runFilter" />
<vue3-tree-org
ref="treeRef"
:data="data"
:filter-node-method="filterNodeMethod"
/>
</template>
<script setup>
import { ref } from 'vue'
const treeRef = ref()
const keyword = ref('')
function filterNodeMethod(value, node) {
if (!value) return true
return String(node.label || '').includes(value)
}
function runFilter() {
treeRef.value.filter(keyword.value)
}
</script>懒加载
开启懒加载需要同时设置 lazy 和 load。如果能提前知道某个节点是不是叶子节点,建议通过 props.isLeaf 映射叶子字段。
<vue3-tree-org
ref="treeRef"
:data="data"
:props="treeProps"
:lazy="true"
:load="loadChildren"
:collapsable="true"
:default-expand-level="0"
/>const treeProps = {
id: 'id',
pid: 'pid',
label: 'label',
children: 'children',
expand: 'expand',
isLeaf: 'isLeaf'
}
const data = {
id: 'root',
pid: '',
label: '懒加载总部',
isLeaf: false
}
function loadChildren(node, resolve) {
const children = [
{
id: `${node.id}-child-1`,
pid: node.id,
label: '懒加载岗位1',
isLeaf: true
}
]
// 组件接口
resolve(children, true)
// 如果业务侧需要同步当前数据,也可以同时写回原始节点
node.$$data.children = children
node.$$data.expand = true
}懒加载注意事项:
- 开启
lazy后,组件默认无法预知没有加载的节点是否还有子级,因此非叶子节点会显示展开按钮。 - 可以用
isLeaf告诉组件当前节点是否叶子节点。 - 开启懒加载后,
default-expand-level、default-expand-keys和工具栏全部展开在复杂场景下可能不适合一起使用。
注释连线
注释通过 annotations 配置,不会写入 children,不会改变组织树结构。
<vue3-tree-org
v-model:annotations="annotations"
:data="data"
:annotation-editable="true"
@on-annotations-change="handleAnnotationsChange"
>
<template #annotation="{ annotation, nodes }">
<div class="custom-annotation">
<strong>{{ Array.isArray(annotation.content) ? annotation.content[0] : annotation.content }}</strong>
<span>{{ nodes.map(item => item.label).join('、') }}</span>
</div>
</template>
</vue3-tree-org>import { ref } from 'vue'
const annotations = ref([
{
id: 'risk-control',
targetKeys: ['inspector', 'monitor'],
content: ['风险管控', '安全部岗位联动'],
color: '#16a34a',
lineStyle: 'solid',
placement: 'bottom',
boxWidth: 220,
boxHeight: 76
},
{
id: 'document-flow',
targetKeys: ['waybill', 'finance'],
content: '单据流转',
color: '#f97316',
lineStyle: 'dashed',
placement: 'bottom',
boxWidth: 180,
boxHeight: 56
}
])
function handleAnnotationsChange(payload) {
// payload.action: add / update / delete
// payload.annotation: 当前变化的注释
// payload.annotations: 最新注释数组
annotations.value = payload.annotations
}annotation-editable = true 后:
- 右键组织节点会追加
新增注释和选择注释。 - 新增或选择注释后会打开内置注释编辑面板。
- 面板中可以编辑注释内容、颜色、线型、位置。
- 面板打开时点击组织节点可以增减注释目标。
- 右键已有注释框可以编辑或删除注释。
注释配置字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | string \| number | 注释唯一标识。 |
| targetKey | string \| number | 连接一个节点。 |
| targetKeys | Array<string \| number> | 连接多个节点。 |
| content | string \| string[] | 注释内容。 |
| color | string | 注释线和边框颜色。 |
| className | string | 注释框自定义 class。 |
| style | object | 注释框自定义行内样式。 |
| lineStyle | 'solid' \| 'dashed' | 连线样式。 |
| lineWidth | number | 连线粗细。 |
| placement | 'auto' \| 'bottom' \| 'right' | 注释位置。 |
| boxAlign | 'target' \| 'tree-bottom' | 注释框定位基准。target 按目标节点定位,tree-bottom 按整棵可见树的最底部定位。 |
| boxGap | number | 注释框和定位基准之间的间距。 |
| boxWidth | number | 注释框布局宽度,会影响连线锚点计算。 |
| boxHeight | number | 注释框布局高度,会影响连线锚点计算。 |
部门 tree 基础用法
部门 tree 使用 <department-tree>。它可以理解为 <vue3-tree-org> 的增强版:原组织树属性、事件、方法、插槽都可以继续传,额外通过 bottomNode 生成底部汇总。
推荐数据格式为:
{
root: {
title: '组织树根节点标题',
type: 1,
members: [],
children: []
},
bottomNode: {
title: '底部汇总标题',
members: [],
children: []
}
}也可以把 bottomNode 直接挂在根节点数据上:
{
title: '组织树根节点标题',
type: 1,
members: [],
children: [],
bottomNode: {
title: '底部汇总标题',
members: [],
children: []
}
}示例:
<template>
<div class="department-page">
<department-tree
:data="data"
:summary-width="560"
:summary-height="150"
:tool-bar="treeTools"
:default-expand-level="8"
:disabled="disabled"
@on-member-name-change="handleMemberNameChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const disabled = ref(false)
const treeTools = {
scale: true,
restore: true,
expand: true,
zoom: true,
fullscreen: true
}
const data = ref({
root: {
title: '安全生产领导小组',
type: 1,
members: [
{ position: '组长', name: '陈荣兴' },
{ position: '副组长', name: '黄臻超' }
],
children: [
{
title: '综合部',
type: 2,
members: [{ position: null, name: '朱湘君' }],
children: [
{
title: '运单管理员',
type: 3,
members: [{ position: null, name: '蒋华琴' }]
},
{
title: '财务人员',
type: 3,
members: [{ position: null, name: '郭荣阁' }]
}
]
},
{
title: '安全部',
type: 2,
members: [{ position: null, name: '黄臻超' }],
children: [
{
title: '专职安全员',
type: 3,
members: [
{ position: null, name: '单筱岑' },
{ position: null, name: '徐俊' },
{ position: null, name: '黄臻超' }
]
},
{
title: '专职监控人员',
type: 3,
members: [
{ position: null, name: '蒋文玉' },
{ position: null, name: '程燕娜' },
{ position: null, name: '李萍' }
]
}
]
},
{
title: '车辆技术管理部',
type: 2,
members: [{ position: null, name: '杨广成' }],
children: [
{
title: '车辆技术管理员',
type: 3,
members: [{ position: null, name: '杨广成' }]
}
]
}
]
},
bottomNode: {
title: '驾驶员、押运员、装卸管理人员',
members: ['蒋华琴', '郭荣阁', '单筱岑', '徐俊', '黄臻超', '蒋文玉', '程燕娜', '李萍', '杨广成'],
children: [
{
title: '驾驶员',
type: 3,
members: [
{ position: null, name: '蒋华琴' },
{ position: null, name: '郭荣阁' },
{ position: null, name: '单筱岑' }
]
},
{
title: '押运员',
type: 3,
members: [
{ position: null, name: '徐俊' },
{ position: null, name: '黄臻超' },
{ position: null, name: '蒋文玉' }
]
},
{
title: '装卸管理人员',
type: 3,
members: [
{ position: null, name: '程燕娜' },
{ position: null, name: '李萍' },
{ position: null, name: '杨广成' }
]
}
]
}
})
function handleMemberNameChange(payload) {
console.log('姓名变更:', payload)
}
</script>
<style scoped>
.department-page {
height: 760px;
background: #fff;
}
</style>部门 tree 数据规则
root
root 是真实组织树,也就是原来传给 <vue3-tree-org> 的树数据主体。<department-tree> 默认仍兼容原组件的 label 显示字段;如果数据只有 title 没有 label,组件会自动用 title 作为显示文本。也可以通过 props.label 映射成其它业务字段。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| title | string | 节点标题,固定展示,不参与编辑。 |
| type | number | 节点类型。1 根节点,2 部门,3 岗位。 |
| members | Array<{ position, name }> | 节点成员,有几条就竖向显示几条。 |
| children | Array | 子节点。 |
| id | string \| number | 可选。不传时组件内部会自动生成。 |
| pid | string \| number | 可选。不传时组件内部会自动生成。 |
| label | string | 可选。默认显示字段仍是原组件的 label;如果没有 label 但有 title,会自动用 title 兜底。 |
成员字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| position | string \| null | 职位。存在时显示为 职位:姓名,为空时只显示姓名。固定展示,不参与编辑。 |
| name | string | 姓名。右键编辑时只编辑这个字段。 |
bottomNode
bottomNode 是组织树之外的底部汇总。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| title | string | 底部汇总标题,固定展示,不参与编辑。 |
| members | string[] | 用于匹配组织树最后一级叶子节点成员姓名。 |
| children | Array | 底部汇总框内的分组展示数据。 |
底部汇总匹配规则:
- 只使用
bottomNode.members中的姓名去匹配。 - 只匹配
root组织树的最后一级叶子节点。 - 不跨级匹配。
- 如果同一个姓名既出现在部门节点,又出现在岗位叶子节点,只会连接最后一级岗位叶子节点。
bottomNode.children只负责底部汇总框内的分组展示,不会被插入root.children。- 底部汇总通过注释层渲染,不改变组织树层级结构。
- 自动生成的底部汇总注释不会回写到业务
annotations,也不会进入普通注释编辑列表。
部门 tree 姓名编辑规则
部门 tree 中:
title固定,不可编辑。position固定,不可编辑。- 只有
members[].name可以编辑。
编辑方式:
- 右键某个组织节点,点击
编辑名称。 - 当前组织节点内所有姓名变为独立输入框。
- 每个姓名可以单独点击、单独输入。
- 点击同一节点内其他姓名输入框时,不会退出编辑态。
- 按 Enter 或输入框失去焦点后保存。
- 保存后触发
on-member-name-change。
底部汇总分组同理:
- 右键底部某个分组,例如
驾驶员。 - 点击
编辑名称。 - 该分组内所有姓名变为独立输入框。
- 每个姓名单独编辑并回写到该分组的
members[].name。
禁用编辑:
<department-tree
:data="data"
:disabled="true"
/>disabled = true 后,组织节点和底部汇总分组都不会显示 编辑名称 菜单。
部门 tree 姓名变更事件
<department-tree
:data="data"
@on-member-name-change="handleMemberNameChange"
/>function handleMemberNameChange(payload) {
console.log(payload)
}事件参数:
{
name: '新姓名',
oldName: '旧姓名',
member: {
position: null,
name: '新姓名'
},
scope: {
key: 'summary:0',
type: 'summary',
title: '驾驶员'
},
index: 0
}字段说明:
| 字段 | 说明 |
| --- | --- |
| name | 修改后的姓名。 |
| oldName | 修改前的姓名。 |
| member | 当前成员对象。 |
| scope.key | 当前编辑范围 key。 |
| scope.type | 编辑来源。tree 表示组织树节点,summary 表示底部汇总分组。 |
| scope.title | 当前组织节点标题或底部分组标题。 |
| index | 当前姓名在成员数组中的下标。 |
部门 tree 自定义组织节点
使用 node 插槽:
<department-tree :data="data">
<template #node="{ node }">
<div class="my-department-node">
<strong>{{ node.$$data.title }}</strong>
<div v-for="member in node.$$data.members" :key="member.name">
<span v-if="member.position">{{ member.position }}:</span>
<span>{{ member.name }}</span>
</div>
</div>
</template>
</department-tree>注意:如果完全自定义 node 插槽,默认的右键姓名编辑 UI 不会自动出现在你的自定义内容里。需要姓名编辑能力时,建议优先使用默认节点样式,或在自定义节点中自行处理编辑交互。
部门 tree 自定义底部汇总
使用 summary 插槽:
<department-tree :data="data">
<template #summary="{ bottomNode, groups }">
<div class="my-summary">
<h3>{{ bottomNode.title }}</h3>
<div class="my-summary-groups">
<section v-for="group in groups" :key="group.key">
<strong>{{ group.title }}</strong>
<span v-for="member in group.members" :key="member.name">
{{ member.name }}
</span>
</section>
</div>
</div>
</template>
</department-tree>注意:如果完全自定义 summary 插槽,默认底部分组右键姓名编辑 UI 不会自动出现在你的自定义内容里。需要姓名编辑能力时,建议优先使用默认汇总样式,或在自定义汇总中自行处理编辑交互。
DepartmentTree Props
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| data | Object | 必填 | 部门树数据,推荐格式为 { root, bottomNode },也支持根节点直接带 bottomNode。 |
| summary-color | String | #111827 | 底部汇总线和汇总框颜色。 |
| summary-width | Number | 560 | 底部汇总框布局宽度,会影响注释锚点计算。 |
| summary-height | Number | 150 | 底部汇总框布局高度,会影响注释锚点计算。 |
| 其它 <vue3-tree-org> 属性 | 同原组件 | 同原组件 | 例如 center、props、tool-bar、horizontal、collapsable、filter-node-method、lazy、load、annotations、annotation-editable、draggable、scalable、node-draggable、selected-key、define-menus 等都可以继续使用。 |
| disabled | Boolean | false | 同原组件禁用规则;在部门 tree 中也会禁用“编辑名称”。 |
Vue3TreeOrg Props
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| data | Object | 必填 | 组织树数据源。 |
| props | Object | { id, pid, label, expand, children } | 字段映射配置。 |
| center | Boolean | false | 是否水平居中。 |
| tool-bar | Object \| Boolean | { expand, scale, zoom, restore, fullscreen } | 工具栏配置。 |
| disabled | Boolean | false | 是否禁用默认新增、编辑、删除。 |
| scalable | Boolean | true | 是否允许缩放。 |
| draggable | Boolean | true | 是否允许拖拽画布。 |
| draggable-on-node | Boolean | false | 是否在节点上触发画布拖拽。 |
| node-draggable | Boolean | true | 是否允许节点拖拽改变结构。 |
| clone-node-drag | Boolean | true | 是否复制节点后拖拽。 |
| only-one-node | Boolean | true | 是否只拖动当前节点。 |
| click-delay | Number | 260 | 单击延迟,用于区分单击和双击。 |
| lazy | Boolean | false | 是否开启懒加载。 |
| load | Function | — | 懒加载方法,格式为 Function(node, resolve)。 |
| default-expand-level | Number | — | 默认展开层级。 |
| default-expand-keys | Array | [] | 默认展开节点 id 数组。 |
| annotations | Array | [] | 注释配置。 |
| annotation-editable | Boolean | false | 是否开启内置右键注释编辑。 |
| before-drag-end | Function | — | 节点拖拽结束前钩子,返回 false 或 rejected Promise 可阻止拖拽。 |
| horizontal | Boolean | false | 是否横向布局。 |
| selected-key | Array \| String \| Number | — | 选中的节点 id 或 id 数组。 |
| collapsable | Boolean | false | 是否可以展开/收起节点。 |
| render-content | Function | — | 自定义节点渲染函数。 |
| label-style | Object | — | 自定义节点样式。 |
| label-class-name | Function \| String | — | 自定义节点 class。 |
| selected-class-name | Function \| String | — | 自定义选中节点 class。 |
| define-menus | Array \| Function | 默认菜单 | 自定义右键菜单。 |
| node-add | Function | — | 覆盖默认新增节点行为。 |
| node-delete | Function | — | 覆盖默认删除节点行为。 |
| node-edit | Function | — | 覆盖默认编辑节点行为。 |
| node-copy | Function | — | 覆盖默认复制文本行为。 |
| filter-node-method | Function | — | 搜索过滤方法。 |
工具栏 tool-bar 配置
const toolBar = {
scale: true,
restore: true,
expand: true,
zoom: true,
fullscreen: true
}| 字段 | 说明 |
| --- | --- |
| scale | 显示当前缩放百分比。 |
| restore | 显示还原按钮。 |
| expand | 显示全部展开/收起按钮。 |
| zoom | 显示放大/缩小按钮。 |
| fullscreen | 显示全屏按钮。 |
如果不需要工具栏:
<vue3-tree-org :data="data" :tool-bar="false" />
<department-tree :data="data" :tool-bar="false" />Events
普通组织树事件:
| 事件名 | 返回值 | 说明 |
| --- | --- | --- |
| on-node-click | (event, data, node) | 节点点击。 |
| on-node-dblclick | (event, data, node) | 节点双击。 |
| on-node-mouseenter | (event, data, node) | 鼠标进入节点。 |
| on-node-mouseleave | (event, data, node) | 鼠标离开节点。 |
| on-node-focus | (event, data, node) | 节点进入编辑。 |
| on-node-blur | (event, data, node) | 节点结束编辑。 |
| on-contextmenu | { command, node, data } | 右键菜单点击。 |
| on-node-copy | text | 复制节点文本。 |
| on-node-delete | data | 删除节点。 |
| on-node-drag-start | node | 节点拖拽开始。 |
| on-node-drag | node | 节点拖拽中。 |
| on-node-drag-end | (node, targetNode) | 节点拖拽结束。 |
| on-expand | (event, data, node) | 节点展开/收起。 |
| on-expand-all | boolean | 全部展开/收起。 |
| on-zoom | scale | 缩放。 |
| on-drag | { x, y } | 画布拖拽中。 |
| on-drag-stop | { x, y } | 画布拖拽结束。 |
| update:annotations | annotations | 注释数组更新,支持 v-model:annotations。 |
| on-annotations-change | { action, annotation, annotations } | 注释新增、编辑、删除。 |
部门 tree 事件:
| 事件名 | 返回值 | 说明 |
| --- | --- | --- |
| on-member-name-change | { name, oldName, member, scope, index } | 成员姓名编辑完成。 |
| 其它 <vue3-tree-org> 事件 | 同原组件 | 例如 on-node-click、on-contextmenu、on-zoom、on-drag、update:annotations 等都可以继续监听。部门 tree 的“编辑名称”菜单向外仍以 command: 'edit' 抛出。 |
Methods
通过 ref 调用:
<vue3-tree-org ref="treeRef" :data="data" />
<department-tree ref="departmentTreeRef" :data="departmentData" />const treeRef = ref()
treeRef.value.filter('财务')
const keys = treeRef.value.getExpandKeys()
treeRef.value.setExpandKeys(['root', 'safety'])
departmentTreeRef.value.filter('安全')
departmentTreeRef.value.setExpandKeys(['department-root'])| 方法 | 参数 | 说明 |
| --- | --- | --- |
| filter | value | 根据 filter-node-method 过滤节点。 |
| getExpandKeys | — | 获取当前展开节点 id 数组。 |
| setExpandKeys | keys | 设置展开节点 id 数组。 |
Slots
普通组织树:
| 插槽名 | 参数 | 说明 |
| --- | --- | --- |
| 默认插槽 | { node } | 自定义节点内容。 |
| expand | { node } | 自定义展开按钮。 |
| annotation | { annotation, nodes } | 自定义注释框内容。 |
部门 tree:
| 插槽名 | 参数 | 说明 |
| --- | --- | --- |
| node | { node } | 自定义部门树组织节点。 |
| summary | { annotation, bottomNode, groups } | 自定义底部汇总框。 |
样式覆盖
组件样式需要先引入:
import '@wsh704/vue3-tree-org-department/lib/vue3-tree-org.css'常用样式覆盖示例:
.department-tree-card {
border-radius: 6px;
}
.department-tree-summary__group {
border-color: #94a3b8;
}
.department-tree-member-name__editor {
width: 6em;
}如果在 Vue 单文件组件里使用 scoped,需要用 :deep():
<style scoped>
:deep(.department-tree-card) {
border-radius: 6px;
}
</style>在业务项目中的推荐接入步骤
- 安装依赖。
npm install @wsh704/vue3-tree-org-department- 在入口文件引入组件库和 CSS。
import treeOrg from '@wsh704/vue3-tree-org-department'
import '@wsh704/vue3-tree-org-department/lib/vue3-tree-org.css'
app.use(treeOrg)普通组织树使用
<vue3-tree-org>。部门 tree 使用
<department-tree>,数据格式保持{ root, bottomNode }。原来传给
<vue3-tree-org>的属性和事件,可以继续传给<department-tree>;只需要把原树数据放到root,并额外增加bottomNode。如果需要姓名编辑,监听
on-member-name-change,在事件里保存到业务状态或调用接口。如果需要禁用编辑,给
department-tree设置:disabled="true"。如果需要自定义 UI,优先通过外层容器和 CSS 覆盖;只有确实需要完全重写时再使用
node或summary插槽。
常见问题
页面没有样式
确认是否引入了 CSS:
import '@wsh704/vue3-tree-org-department/lib/vue3-tree-org.css'<department-tree> 不显示
检查:
- 是否执行了
app.use(treeOrg)。 - 是否从正确包名引入:
@wsh704/vue3-tree-org-department。 data是否包含bottomNode。推荐格式是{ root, bottomNode };如果直接传根节点,则根节点上需要有bottomNode。- 容器是否有高度,例如
height: 760px。
部门 tree 为什么只连接最后一级
这是当前业务规则。bottomNode.members 只匹配组织树最后一级叶子节点,不匹配部门、根节点等上级节点。
部门 tree 可以编辑 title 吗
不可以。当前规则是:
title固定。position固定。- 只有姓名
members[].name可以右键编辑。
多个姓名编辑时点击另一个输入框会退出吗
不会。同一个组织节点或底部分组内,多个姓名输入框可以互相点击切换,只有点击到编辑范围外或按 Enter 失焦后才退出编辑态。
右键没有“编辑名称”
检查:
- 是否右键在组织节点卡片或底部汇总分组上。
department-tree是否设置了disabled=true。- 当前节点或分组是否有
members。
需要同时保留旧组织树功能和新增部门 tree
可以。这个包同时导出并注册:
<vue3-tree-org><department-tree>
在同一个项目里可以同时使用,两者不会冲突。<department-tree> 本身也是基于原 <vue3-tree-org> 的增强封装,原组件的大部分属性、事件、方法都能继续使用;特色能力只来自额外的 bottomNode。
验证记录
已在 treeOrg/vue3-demo 中完成真实 npm 安装和多功能验证:
npm run build通过。- 基础树、自定义节点、自定义注释、注释连线、缩放通过。
- 搜索过滤通过。
- 懒加载通过。
- 默认右键菜单编辑、新增、删除通过。
- 自定义右键菜单通过。
- 部门 tree 渲染、叶子匹配、底部汇总、姓名编辑、disabled 禁用编辑通过。
- 页面 runtime errors 为空。
验证页面:
http://localhost:8088/#/tree-org-npm