@ticatec/uniface-element 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accordion/README.md +169 -0
- package/dist/accordion/README_CN.md +176 -0
- package/dist/action-bar/README.md +275 -0
- package/dist/action-bar/README_CN.md +285 -0
- package/dist/app-layout/README.md +374 -0
- package/dist/app-layout/README_CN.md +381 -0
- package/dist/app-top-bar/README.md +357 -0
- package/dist/app-top-bar/README_CN.md +365 -0
- package/dist/attachment-files/AttachmentFilesField.svelte +67 -1
- package/dist/attachment-files/AttachmentFilesField.svelte.d.ts +8 -1
- package/dist/base-calendar/CalendarBase.svelte +0 -3
- package/dist/box/README.md +385 -0
- package/dist/box/README_CN.md +393 -0
- package/dist/breadcrumbs/README.md +442 -0
- package/dist/breadcrumbs/README_CN.md +442 -0
- package/dist/button/Button.svelte +27 -7
- package/dist/button/Button.svelte.d.ts +3 -1
- package/dist/button/IconButton.svelte +26 -6
- package/dist/button/IconButton.svelte.d.ts +3 -1
- package/dist/button/IconButton_README.md +513 -0
- package/dist/button/IconButton_README_CN.md +513 -0
- package/dist/button/README.md +428 -0
- package/dist/button/README_CN.md +428 -0
- package/dist/button/TextButton.svelte +26 -6
- package/dist/button/TextButton.svelte.d.ts +3 -1
- package/dist/button/TextButton_README.md +571 -0
- package/dist/button/TextButton_README_CN.md +571 -0
- package/dist/card/README.md +666 -0
- package/dist/card/README_CN.md +666 -0
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +43 -7
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +3 -4
- package/dist/cascade-options-select/README.md +663 -2
- package/dist/cascade-options-select/README_CN.md +664 -0
- package/dist/checkbox/CheckBox.svelte +20 -6
- package/dist/checkbox/CheckBox.svelte.d.ts +4 -2
- package/dist/checkbox/README.md +562 -0
- package/dist/checkbox/README_CN.md +727 -0
- package/dist/common-editor/NumberInput.svelte +39 -26
- package/dist/common-editor/NumberInput.svelte.d.ts +5 -1
- package/dist/concise-data-table/ConciseListTable.svelte +133 -36
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +8 -1
- package/dist/concise-data-table/DataCell.svelte +5 -6
- package/dist/concise-data-table/DataRow.svelte +22 -2
- package/dist/concise-data-table/DataRow.svelte.d.ts +1 -0
- package/dist/concise-data-table/README.md +606 -0
- package/dist/concise-data-table/README_CN.md +611 -0
- package/dist/context-menu/ContextMenu.svelte +138 -21
- package/dist/context-menu/ContextMenu.svelte.d.ts +5 -0
- package/dist/context-menu/ContextMenuItem.d.ts +20 -4
- package/dist/context-menu/README.md +551 -0
- package/dist/context-menu/README_CN.md +551 -0
- package/dist/criteria-field/CriteriaField.svelte +3 -5
- package/dist/criteria-field/README.md +532 -0
- package/dist/criteria-field/README_CN.md +532 -0
- package/dist/data-table/README.md +712 -0
- package/dist/data-table/README_CN.md +712 -0
- package/dist/date-picker/DatePicker.svelte +44 -7
- package/dist/date-picker/DatePicker.svelte.d.ts +3 -4
- package/dist/date-picker/DateTimePicker.svelte +32 -8
- package/dist/date-picker/DateTimePicker.svelte.d.ts +3 -4
- package/dist/date-picker/README.md +326 -0
- package/dist/date-picker/README_CN.md +316 -0
- package/dist/date-picker/ScrollBar.svelte +18 -8
- package/dist/date-picker/ScrollBar.svelte.d.ts +1 -1
- package/dist/date-picker/TimePanel.svelte +5 -5
- package/dist/date-picker/TimePanel.svelte.d.ts +1 -1
- package/dist/date-range/README.md +374 -0
- package/dist/date-range/README_CN.md +374 -0
- package/dist/dialog/README.md +596 -0
- package/dist/dialog/README_CN.md +596 -0
- package/dist/drawer/README.md +679 -1
- package/dist/drawer/README_CN.md +679 -0
- package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
- package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
- package/dist/group-box/group-check-box/README.md +749 -0
- package/dist/group-box/group-check-box/README_CN.md +750 -0
- package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
- package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
- package/dist/group-box/group-radio-box/README.md +920 -0
- package/dist/group-box/group-radio-box/README_CN.md +920 -0
- package/dist/image-files/README.md +1346 -0
- package/dist/image-files/README_CN.md +1346 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
- package/dist/lib/forwardAllEvents.d.ts +3 -0
- package/dist/lib/forwardAllEvents.js +24 -0
- package/dist/list-box/README.md +579 -0
- package/dist/list-box/README_CN.md +682 -0
- package/dist/lookup-editor/LookupEditor.svelte +15 -3
- package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
- package/dist/lookup-editor/README.md +684 -0
- package/dist/lookup-editor/README_CN.md +684 -0
- package/dist/memo-editor/MemoEditor.svelte +77 -27
- package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
- package/dist/memo-editor/README.md +819 -0
- package/dist/memo-editor/README_CN.md +819 -0
- package/dist/message-box/README.md +398 -0
- package/dist/message-box/README_CN.md +398 -0
- package/dist/number-editor/NumberEditor.svelte +2 -2
- package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
- package/dist/number-editor/README.md +353 -22
- package/dist/number-editor/README_CN.md +357 -0
- package/dist/number-range/README.md +443 -0
- package/dist/number-range/README_CN.md +443 -0
- package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
- package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
- package/dist/options-multi-select/README.md +480 -0
- package/dist/options-multi-select/README_CN.md +480 -0
- package/dist/options-select/OptionsSelect.svelte +36 -5
- package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
- package/dist/options-select/README.md +632 -0
- package/dist/options-select/README_CN.md +632 -0
- package/dist/page/README.md +605 -0
- package/dist/page/README_CN.md +605 -0
- package/dist/pagination/README.md +946 -0
- package/dist/pagination/README_CN.md +946 -0
- package/dist/pagination-panel/README.md +1075 -0
- package/dist/pagination-panel/README_CN.md +1075 -0
- package/dist/popup-hint/README.md +841 -0
- package/dist/popup-hint/README_CN.md +840 -0
- package/dist/progress-bar/README.md +242 -0
- package/dist/progress-bar/README_CN.md +242 -0
- package/dist/progress-step-bar/README.md +316 -0
- package/dist/progress-step-bar/README_CN.md +316 -0
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
- package/dist/prompts-text-editor/README.md +329 -0
- package/dist/prompts-text-editor/README_CN.md +329 -0
- package/dist/property-editor/README.md +969 -0
- package/dist/property-editor/README_CN.md +969 -0
- package/dist/radio-button/README.md +372 -0
- package/dist/radio-button/README_CN.md +372 -0
- package/dist/radio-button/RadioButton.svelte +32 -3
- package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
- package/dist/search-box/README.md +425 -0
- package/dist/search-box/README_CN.md +424 -0
- package/dist/search-box/SearchBox.svelte +22 -6
- package/dist/search-box/SearchBox.svelte.d.ts +4 -1
- package/dist/tabs/README.md +919 -0
- package/dist/tabs/README_CN.md +920 -0
- package/dist/tag/README.md +922 -0
- package/dist/tag/README_CN.md +922 -0
- package/dist/text-editor/PasswordEditor.svelte +17 -2
- package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
- package/dist/text-editor/PasswordEditor_README.md +551 -0
- package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
- package/dist/text-editor/README.md +466 -0
- package/dist/text-editor/README_CN.md +466 -0
- package/dist/text-editor/TextEditor.svelte +51 -19
- package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
- package/dist/time-editor/README.md +498 -24
- package/dist/time-editor/README_CN.md +498 -0
- package/dist/time-editor/TimeEditor.svelte +7 -3
- package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
- package/dist/toast/README.md +667 -0
- package/dist/toast/README_CN.md +667 -0
- package/dist/transfer/README.md +795 -0
- package/dist/transfer/Transfer.svelte +6 -4
- package/dist/transfer/Transfer.svelte.d.ts +3 -1
- package/dist/tree-view/README.md +761 -0
- package/dist/tree-view/README_CN.md +761 -0
- package/dist/tree-view/TreeView.svelte +5 -3
- package/dist/tree-view/TreeView.svelte.d.ts +3 -1
- package/dist/unit-number-editor/README.md +546 -20
- package/dist/unit-number-editor/README_CN.md +525 -0
- package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
- package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
- package/docs/form-field/cn/README_CN.md +364 -0
- package/docs/form-field/en/README.md +364 -0
- package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
- package/docs/form-panel/flex-form/en/README.md +586 -0
- package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
- package/docs/form-panel/flex-row-form/en/README.md +787 -0
- package/docs/form-panel/grid-form/en/README.md +744 -0
- package/package.json +1 -1
- package/dist/drawer/README-CN.md +0 -1
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
# 树视图组件
|
|
2
|
+
|
|
3
|
+
一个用于展示嵌套数据结构的层级树视图组件。支持可展开/折叠的节点、延迟加载、上下文菜单和自定义节点显示。非常适合文件浏览器、组织结构图和层级数据导航。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ticatec/uniface-element
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 导入
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import TreeView, { type LazyLoader, type NodeVisibleFun, type OnNodeSelectionChange } from "@ticatec/uniface-element/TreeView";
|
|
15
|
+
import TreeNodes, { type TreeNode } from "@ticatec/uniface-element/TreeNodes";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 基本用法
|
|
19
|
+
|
|
20
|
+
```svelte
|
|
21
|
+
<script>
|
|
22
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
23
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
24
|
+
|
|
25
|
+
let activeNode = null;
|
|
26
|
+
|
|
27
|
+
// 示例数据
|
|
28
|
+
const data = [
|
|
29
|
+
{ id: 1, name: "文档", parent: null },
|
|
30
|
+
{ id: 2, name: "项目", parent: null },
|
|
31
|
+
{ id: 3, name: "项目 A", parent: 2 },
|
|
32
|
+
{ id: 4, name: "项目 B", parent: 2 },
|
|
33
|
+
{ id: 5, name: "文件1.txt", parent: 3 },
|
|
34
|
+
{ id: 6, name: "文件2.txt", parent: 3 }
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
// 创建树结构
|
|
38
|
+
const treeNodes = new TreeNodes({
|
|
39
|
+
keyField: 'id',
|
|
40
|
+
textField: 'name',
|
|
41
|
+
parentKeyField: 'parent',
|
|
42
|
+
checkIsRoot: (item) => item.parent === null,
|
|
43
|
+
checkIsDirectory: (node) => node.children != null
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
treeNodes.setData(data);
|
|
47
|
+
|
|
48
|
+
function handleSelectionChange(node) {
|
|
49
|
+
console.log('选中节点:', node);
|
|
50
|
+
return true; // 允许选择
|
|
51
|
+
}
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<TreeView
|
|
55
|
+
nodes={treeNodes.nodes}
|
|
56
|
+
textField="name"
|
|
57
|
+
bind:activeNode
|
|
58
|
+
onchange={handleSelectionChange}
|
|
59
|
+
checkIsDirectory={node => node.children != null}
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 属性
|
|
64
|
+
|
|
65
|
+
| 属性 | 类型 | 默认值 | 描述 |
|
|
66
|
+
|------|------|---------|-------------|
|
|
67
|
+
| `nodes` | `Array<TreeNode<any>>` | 必需 | 要显示的树节点数组 |
|
|
68
|
+
| `textField` | `string \| GetText<any>` | 必需 | 节点文本的字段名称或获取文本的函数 |
|
|
69
|
+
| `activeNode` | `any` | `null` | 当前选中的/活动节点 |
|
|
70
|
+
| `style` | `string` | `""` | 附加 CSS 样式 |
|
|
71
|
+
| `lazyLoader` | `LazyLoader \| null` | `null` | 延迟加载配置 |
|
|
72
|
+
| `isVisible` | `NodeVisibleFun` | `null` | 判断节点可见性的函数 |
|
|
73
|
+
| `onchange` | `OnNodeSelectionChange` | `null` | 节点选择更改时的回调函数 |
|
|
74
|
+
| `onfocus` | `((event: FocusEvent) => void) \| null` | `null` | 树获得焦点时的回调函数 |
|
|
75
|
+
| `onblur` | `((event: FocusEvent) => void) \| null` | `null` | 树失去焦点时的回调函数 |
|
|
76
|
+
| `onContextMenu` | `OnContextMenu` | `null` | 右键上下文菜单处理程序 |
|
|
77
|
+
| `checkIsDirectory` | `CheckIsDirectory<any>` | 必需 | 判断节点是否为目录的函数 |
|
|
78
|
+
| `class` | `string` | `""` | CSS 类名 |
|
|
79
|
+
|
|
80
|
+
## 类型定义
|
|
81
|
+
|
|
82
|
+
### TreeNode<T>
|
|
83
|
+
```typescript
|
|
84
|
+
interface TreeNode<T> {
|
|
85
|
+
item: T; // 实际数据项
|
|
86
|
+
children?: Array<TreeNode<T>>; // 子节点
|
|
87
|
+
expand?: boolean; // 节点是否展开
|
|
88
|
+
parent?: TreeNode<T>; // 父节点引用
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### LazyLoader
|
|
93
|
+
```typescript
|
|
94
|
+
interface LazyLoader {
|
|
95
|
+
isBranch: (node: TreeNode<any>) => boolean; // 判断节点是否可有子节点
|
|
96
|
+
load: (node: TreeNode<any>) => Promise<Array<TreeNode<any>>>; // 加载子节点
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### OnNodeSelectionChange
|
|
101
|
+
```typescript
|
|
102
|
+
type OnNodeSelectionChange = (node: TreeNode<any>) => Promise<boolean>;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### NodeVisibleFun
|
|
106
|
+
```typescript
|
|
107
|
+
type NodeVisibleFun = (node: TreeNode<any>) => boolean;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 示例
|
|
111
|
+
|
|
112
|
+
### 文件系统树
|
|
113
|
+
|
|
114
|
+
```svelte
|
|
115
|
+
<script>
|
|
116
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
117
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
118
|
+
|
|
119
|
+
let activeNode = null;
|
|
120
|
+
|
|
121
|
+
const fileSystemData = [
|
|
122
|
+
{ id: 1, name: "📁 文档", type: "folder", parent: null },
|
|
123
|
+
{ id: 2, name: "📁 图片", type: "folder", parent: null },
|
|
124
|
+
{ id: 3, name: "📁 工作", type: "folder", parent: 1 },
|
|
125
|
+
{ id: 4, name: "📁 个人", type: "folder", parent: 1 },
|
|
126
|
+
{ id: 5, name: "📄 简历.pdf", type: "file", parent: 3 },
|
|
127
|
+
{ id: 6, name: "📄 求职信.doc", type: "file", parent: 3 },
|
|
128
|
+
{ id: 7, name: "🖼️ 度假.jpg", type: "file", parent: 2 },
|
|
129
|
+
{ id: 8, name: "🖼️ 家庭.png", type: "file", parent: 2 }
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
const fileTree = new TreeNodes({
|
|
133
|
+
keyField: 'id',
|
|
134
|
+
textField: 'name',
|
|
135
|
+
parentKeyField: 'parent',
|
|
136
|
+
checkIsRoot: (item) => item.parent === null,
|
|
137
|
+
checkIsDirectory: (node) => node.item.type === 'folder',
|
|
138
|
+
expendDepth: 1 // 默认展开第一层
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
fileTree.setData(fileSystemData);
|
|
142
|
+
|
|
143
|
+
function handleFileSelection(node) {
|
|
144
|
+
console.log('选中文件:', node.item.name);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isDirectory(node) {
|
|
149
|
+
return node.item.type === 'folder';
|
|
150
|
+
}
|
|
151
|
+
</script>
|
|
152
|
+
|
|
153
|
+
<div class="file-explorer">
|
|
154
|
+
<h3>文件浏览器</h3>
|
|
155
|
+
<TreeView
|
|
156
|
+
nodes={fileTree.nodes}
|
|
157
|
+
textField="name"
|
|
158
|
+
bind:activeNode
|
|
159
|
+
onchange={handleFileSelection}
|
|
160
|
+
checkIsDirectory={isDirectory}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<style>
|
|
165
|
+
.file-explorer {
|
|
166
|
+
width: 300px;
|
|
167
|
+
border: 1px solid #ddd;
|
|
168
|
+
border-radius: 4px;
|
|
169
|
+
padding: 16px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
h3 {
|
|
173
|
+
margin: 0 0 12px 0;
|
|
174
|
+
font-size: 16px;
|
|
175
|
+
}
|
|
176
|
+
</style>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 组织结构图
|
|
180
|
+
|
|
181
|
+
```svelte
|
|
182
|
+
<script>
|
|
183
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
184
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
185
|
+
|
|
186
|
+
let selectedEmployee = null;
|
|
187
|
+
|
|
188
|
+
const orgData = [
|
|
189
|
+
{ id: 1, name: "首席执行官 - 张伟", position: "首席执行官", manager: null },
|
|
190
|
+
{ id: 2, name: "技术总监 - 李娜", position: "技术总监", manager: 1 },
|
|
191
|
+
{ id: 3, name: "财务总监 - 王强", position: "财务总监", manager: 1 },
|
|
192
|
+
{ id: 4, name: "开发经理 - 刘芳", position: "开发经理", manager: 2 },
|
|
193
|
+
{ id: 5, name: "质量经理 - 陈明", position: "质量经理", manager: 2 },
|
|
194
|
+
{ id: 6, name: "开发者 - 赵丽", position: "高级开发者", manager: 4 },
|
|
195
|
+
{ id: 7, name: "开发者 - 孙洋", position: "初级开发者", manager: 4 },
|
|
196
|
+
{ id: 8, name: "质量工程师 - 周洁", position: "质量工程师", manager: 5 }
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
const orgChart = new TreeNodes({
|
|
200
|
+
keyField: 'id',
|
|
201
|
+
textField: 'name',
|
|
202
|
+
parentKeyField: 'manager',
|
|
203
|
+
checkIsRoot: (item) => item.manager === null,
|
|
204
|
+
checkIsDirectory: (node) => node.children && node.children.length > 0,
|
|
205
|
+
expendDepth: 2
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
orgChart.setData(orgData);
|
|
209
|
+
|
|
210
|
+
function handleEmployeeSelection(node) {
|
|
211
|
+
selectedEmployee = node.item;
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function isManager(node) {
|
|
216
|
+
return node.children && node.children.length > 0;
|
|
217
|
+
}
|
|
218
|
+
</script>
|
|
219
|
+
|
|
220
|
+
<div class="org-chart">
|
|
221
|
+
<h3>组织结构图</h3>
|
|
222
|
+
<TreeView
|
|
223
|
+
nodes={orgChart.nodes}
|
|
224
|
+
textField="name"
|
|
225
|
+
onchange={handleEmployeeSelection}
|
|
226
|
+
checkIsDirectory={isManager}
|
|
227
|
+
/>
|
|
228
|
+
|
|
229
|
+
{#if selectedEmployee}
|
|
230
|
+
<div class="employee-details">
|
|
231
|
+
<h4>员工详情</h4>
|
|
232
|
+
<p><strong>姓名:</strong> {selectedEmployee.name}</p>
|
|
233
|
+
<p><strong>职位:</strong> {selectedEmployee.position}</p>
|
|
234
|
+
</div>
|
|
235
|
+
{/if}
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<style>
|
|
239
|
+
.org-chart {
|
|
240
|
+
width: 400px;
|
|
241
|
+
border: 1px solid #ddd;
|
|
242
|
+
border-radius: 4px;
|
|
243
|
+
padding: 16px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.employee-details {
|
|
247
|
+
margin-top: 16px;
|
|
248
|
+
padding: 12px;
|
|
249
|
+
background: #f8f9fa;
|
|
250
|
+
border-radius: 4px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.employee-details h4 {
|
|
254
|
+
margin: 0 0 8px 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.employee-details p {
|
|
258
|
+
margin: 4px 0;
|
|
259
|
+
}
|
|
260
|
+
</style>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 延迟加载
|
|
264
|
+
|
|
265
|
+
```svelte
|
|
266
|
+
<script>
|
|
267
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
268
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
269
|
+
|
|
270
|
+
let activeNode = null;
|
|
271
|
+
|
|
272
|
+
// 初始根节点
|
|
273
|
+
const initialData = [
|
|
274
|
+
{ id: 1, name: "文件夹 A", hasChildren: true },
|
|
275
|
+
{ id: 2, name: "文件夹 B", hasChildren: true },
|
|
276
|
+
{ id: 3, name: "文件 1.txt", hasChildren: false }
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
const treeNodes = new TreeNodes({
|
|
280
|
+
keyField: 'id',
|
|
281
|
+
textField: 'name',
|
|
282
|
+
parentKeyField: 'parent',
|
|
283
|
+
checkIsRoot: (item) => !item.parent,
|
|
284
|
+
checkIsDirectory: (node) => node.item.hasChildren
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
treeNodes.setData(initialData);
|
|
288
|
+
|
|
289
|
+
// 延迟加载配置
|
|
290
|
+
const lazyLoader = {
|
|
291
|
+
isBranch: (node) => node.item.hasChildren,
|
|
292
|
+
|
|
293
|
+
load: async (node) => {
|
|
294
|
+
// 模拟 API 调用
|
|
295
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
296
|
+
|
|
297
|
+
// 生成子节点
|
|
298
|
+
const children = [];
|
|
299
|
+
for (let i = 1; i <= 3; i++) {
|
|
300
|
+
children.push({
|
|
301
|
+
id: `${node.item.id}-${i}`,
|
|
302
|
+
name: `${node.item.name} - 子节点 ${i}`,
|
|
303
|
+
parent: node.item.id,
|
|
304
|
+
hasChildren: Math.random() > 0.7 // 30% 概率有子节点
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return children.map(child => ({ item: child, children: null }));
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
function handleSelection(node) {
|
|
313
|
+
console.log('选中:', node.item.name);
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function isDirectory(node) {
|
|
318
|
+
return node.item.hasChildren;
|
|
319
|
+
}
|
|
320
|
+
</script>
|
|
321
|
+
|
|
322
|
+
<div class="lazy-tree">
|
|
323
|
+
<h3>延迟加载树</h3>
|
|
324
|
+
<TreeView
|
|
325
|
+
nodes={treeNodes.nodes}
|
|
326
|
+
textField="name"
|
|
327
|
+
bind:activeNode
|
|
328
|
+
{lazyLoader}
|
|
329
|
+
onchange={handleSelection}
|
|
330
|
+
checkIsDirectory={isDirectory}
|
|
331
|
+
/>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<style>
|
|
335
|
+
.lazy-tree {
|
|
336
|
+
width: 300px;
|
|
337
|
+
border: 1px solid #ddd;
|
|
338
|
+
border-radius: 4px;
|
|
339
|
+
padding: 16px;
|
|
340
|
+
}
|
|
341
|
+
</style>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### 带上下文菜单
|
|
345
|
+
|
|
346
|
+
```svelte
|
|
347
|
+
<script>
|
|
348
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
349
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
350
|
+
import ContextMenu from "@ticatec/uniface-element/ContextMenu";
|
|
351
|
+
|
|
352
|
+
let activeNode = null;
|
|
353
|
+
let contextMenu;
|
|
354
|
+
|
|
355
|
+
const menuData = [
|
|
356
|
+
{ id: 1, name: "根文件夹", type: "folder", parent: null },
|
|
357
|
+
{ id: 2, name: "子文件夹", type: "folder", parent: 1 },
|
|
358
|
+
{ id: 3, name: "文档.txt", type: "file", parent: 2 }
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
const menuTree = new TreeNodes({
|
|
362
|
+
keyField: 'id',
|
|
363
|
+
textField: 'name',
|
|
364
|
+
parentKeyField: 'parent',
|
|
365
|
+
checkIsRoot: (item) => item.parent === null,
|
|
366
|
+
checkIsDirectory: (node) => node.item.type === 'folder'
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
menuTree.setData(menuData);
|
|
370
|
+
|
|
371
|
+
function handleContextMenu(event, node) {
|
|
372
|
+
const isFolder = node.item.type === 'folder';
|
|
373
|
+
|
|
374
|
+
const menuItems = [
|
|
375
|
+
{
|
|
376
|
+
text: "打开",
|
|
377
|
+
action: () => console.log('打开:', node.item.name)
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
text: "重命名",
|
|
381
|
+
action: () => console.log('重命名:', node.item.name)
|
|
382
|
+
},
|
|
383
|
+
...(isFolder ? [{
|
|
384
|
+
text: "添加文件",
|
|
385
|
+
action: () => console.log('添加文件到:', node.item.name)
|
|
386
|
+
}] : []),
|
|
387
|
+
{
|
|
388
|
+
text: "删除",
|
|
389
|
+
action: () => console.log('删除:', node.item.name)
|
|
390
|
+
}
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
contextMenu.show(event, menuItems);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isDirectory(node) {
|
|
397
|
+
return node.item.type === 'folder';
|
|
398
|
+
}
|
|
399
|
+
</script>
|
|
400
|
+
|
|
401
|
+
<div class="context-tree">
|
|
402
|
+
<h3>右键显示上下文菜单</h3>
|
|
403
|
+
<TreeView
|
|
404
|
+
nodes={menuTree.nodes}
|
|
405
|
+
textField="name"
|
|
406
|
+
bind:activeNode
|
|
407
|
+
onContextMenu={handleContextMenu}
|
|
408
|
+
checkIsDirectory={isDirectory}
|
|
409
|
+
/>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<ContextMenu bind:this={contextMenu} />
|
|
413
|
+
|
|
414
|
+
<style>
|
|
415
|
+
.context-tree {
|
|
416
|
+
width: 300px;
|
|
417
|
+
border: 1px solid #ddd;
|
|
418
|
+
border-radius: 4px;
|
|
419
|
+
padding: 16px;
|
|
420
|
+
}
|
|
421
|
+
</style>
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### 带自定义可见性过滤
|
|
425
|
+
|
|
426
|
+
```svelte
|
|
427
|
+
<script>
|
|
428
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
429
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
430
|
+
|
|
431
|
+
let activeNode = null;
|
|
432
|
+
let showHidden = false;
|
|
433
|
+
|
|
434
|
+
const fileData = [
|
|
435
|
+
{ id: 1, name: "public", hidden: false, parent: null },
|
|
436
|
+
{ id: 2, name: ".env", hidden: true, parent: null },
|
|
437
|
+
{ id: 3, name: "index.js", hidden: false, parent: 1 },
|
|
438
|
+
{ id: 4, name: ".gitignore", hidden: true, parent: 1 },
|
|
439
|
+
{ id: 5, name: "config.json", hidden: false, parent: 1 }
|
|
440
|
+
];
|
|
441
|
+
|
|
442
|
+
const fileTree = new TreeNodes({
|
|
443
|
+
keyField: 'id',
|
|
444
|
+
textField: 'name',
|
|
445
|
+
parentKeyField: 'parent',
|
|
446
|
+
checkIsRoot: (item) => item.parent === null,
|
|
447
|
+
checkIsDirectory: (node) => node.children && node.children.length > 0
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
fileTree.setData(fileData);
|
|
451
|
+
|
|
452
|
+
function isVisible(node) {
|
|
453
|
+
return showHidden || !node.item.hidden;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function isDirectory(node) {
|
|
457
|
+
return node.children && node.children.length > 0;
|
|
458
|
+
}
|
|
459
|
+
</script>
|
|
460
|
+
|
|
461
|
+
<div class="filtered-tree">
|
|
462
|
+
<div class="controls">
|
|
463
|
+
<label>
|
|
464
|
+
<input type="checkbox" bind:checked={showHidden} />
|
|
465
|
+
显示隐藏文件
|
|
466
|
+
</label>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
<TreeView
|
|
470
|
+
nodes={fileTree.nodes}
|
|
471
|
+
textField="name"
|
|
472
|
+
bind:activeNode
|
|
473
|
+
{isVisible}
|
|
474
|
+
checkIsDirectory={isDirectory}
|
|
475
|
+
/>
|
|
476
|
+
</div>
|
|
477
|
+
|
|
478
|
+
<style>
|
|
479
|
+
.filtered-tree {
|
|
480
|
+
width: 300px;
|
|
481
|
+
border: 1px solid #ddd;
|
|
482
|
+
border-radius: 4px;
|
|
483
|
+
padding: 16px;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.controls {
|
|
487
|
+
margin-bottom: 12px;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
label {
|
|
491
|
+
display: flex;
|
|
492
|
+
align-items: center;
|
|
493
|
+
gap: 8px;
|
|
494
|
+
font-size: 14px;
|
|
495
|
+
}
|
|
496
|
+
</style>
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### 带事件处理程序
|
|
500
|
+
|
|
501
|
+
```svelte
|
|
502
|
+
<script>
|
|
503
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
504
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
505
|
+
|
|
506
|
+
let activeNode = null;
|
|
507
|
+
let isFocused = false;
|
|
508
|
+
let selectionLog = [];
|
|
509
|
+
|
|
510
|
+
const eventData = [
|
|
511
|
+
{ id: 1, name: "节点 1", parent: null },
|
|
512
|
+
{ id: 2, name: "节点 2", parent: null },
|
|
513
|
+
{ id: 3, name: "子节点 1", parent: 1 },
|
|
514
|
+
{ id: 4, name: "子节点 2", parent: 1 }
|
|
515
|
+
];
|
|
516
|
+
|
|
517
|
+
const eventTree = new TreeNodes({
|
|
518
|
+
keyField: 'id',
|
|
519
|
+
textField: 'name',
|
|
520
|
+
parentKeyField: 'parent',
|
|
521
|
+
checkIsRoot: (item) => item.parent === null,
|
|
522
|
+
checkIsDirectory: (node) => node.children && node.children.length > 0
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
eventTree.setData(eventData);
|
|
526
|
+
|
|
527
|
+
function handleSelectionChange(node) {
|
|
528
|
+
selectionLog = [...selectionLog, `选中:${node.item.name} 在 ${new Date().toLocaleTimeString()}`];
|
|
529
|
+
return true;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function handleFocus(event) {
|
|
533
|
+
console.log('树已聚焦');
|
|
534
|
+
isFocused = true;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function handleBlur(event) {
|
|
538
|
+
console.log('树已失焦');
|
|
539
|
+
isFocused = false;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function isDirectory(node) {
|
|
543
|
+
return node.children && node.children.length > 0;
|
|
544
|
+
}
|
|
545
|
+
</script>
|
|
546
|
+
|
|
547
|
+
<div class="event-tree">
|
|
548
|
+
<h3>事件处理演示</h3>
|
|
549
|
+
<p>树当前 {isFocused ? '已聚焦' : '未聚焦'}</p>
|
|
550
|
+
|
|
551
|
+
<TreeView
|
|
552
|
+
nodes={eventTree.nodes}
|
|
553
|
+
textField="name"
|
|
554
|
+
bind:activeNode
|
|
555
|
+
onchange={handleSelectionChange}
|
|
556
|
+
onfocus={handleFocus}
|
|
557
|
+
onblur={handleBlur}
|
|
558
|
+
checkIsDirectory={isDirectory}
|
|
559
|
+
/>
|
|
560
|
+
|
|
561
|
+
<div class="log">
|
|
562
|
+
<h4>选择日志:</h4>
|
|
563
|
+
{#each selectionLog.slice(-5) as entry}
|
|
564
|
+
<p>{entry}</p>
|
|
565
|
+
{/each}
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
|
|
569
|
+
<style>
|
|
570
|
+
.event-tree {
|
|
571
|
+
width: 400px;
|
|
572
|
+
border: 1px solid #ddd;
|
|
573
|
+
border-radius: 4px;
|
|
574
|
+
padding: 16px;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.log {
|
|
578
|
+
margin-top: 16px;
|
|
579
|
+
padding: 12px;
|
|
580
|
+
background: #f8f9fa;
|
|
581
|
+
border-radius: 4px;
|
|
582
|
+
max-height: 150px;
|
|
583
|
+
overflow-y: auto;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.log h4 {
|
|
587
|
+
margin: 0 0 8px 0;
|
|
588
|
+
font-size: 14px;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.log p {
|
|
592
|
+
margin: 2px 0;
|
|
593
|
+
font-size: 12px;
|
|
594
|
+
font-family: monospace;
|
|
595
|
+
}
|
|
596
|
+
</style>
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### 地理层级
|
|
600
|
+
|
|
601
|
+
```svelte
|
|
602
|
+
<script>
|
|
603
|
+
import TreeView from "@ticatec/uniface-element/TreeView";
|
|
604
|
+
import TreeNodes from "@ticatec/uniface-element/TreeNodes";
|
|
605
|
+
|
|
606
|
+
let activeLocation = null;
|
|
607
|
+
|
|
608
|
+
const locationData = [
|
|
609
|
+
{ code: "CN", name: "中国", type: "country", parent: null },
|
|
610
|
+
{ code: "US", name: "美国", type: "country", parent: null },
|
|
611
|
+
{ code: "CN-BJ", name: "北京", type: "province", parent: "CN" },
|
|
612
|
+
{ code: "CN-SH", name: "上海", type: "province", parent: "CN" },
|
|
613
|
+
{ code: "US-CA", name: "加利福尼亚", type: "state", parent: "US" },
|
|
614
|
+
{ code: "US-NY", name: "纽约", type: "state", parent: "US" },
|
|
615
|
+
{ code: "CN-BJ-HD", name: "海淀区", type: "district", parent: "CN-BJ" },
|
|
616
|
+
{ code: "CN-BJ-CY", name: "朝阳区", type: "district", parent: "CN-BJ" },
|
|
617
|
+
{ code: "US-CA-SF", name: "旧金山", type: "city", parent: "US-CA" },
|
|
618
|
+
{ code: "US-CA-LA", name: "洛杉矶", type: "city", parent: "US-CA" }
|
|
619
|
+
];
|
|
620
|
+
|
|
621
|
+
const locationTree = new TreeNodes({
|
|
622
|
+
keyField: 'code',
|
|
623
|
+
textField: 'name',
|
|
624
|
+
parentKeyField: 'parent',
|
|
625
|
+
checkIsRoot: (item) => item.parent === null,
|
|
626
|
+
checkIsDirectory: (node) => {
|
|
627
|
+
const hasChildren = locationData.some(loc => loc.parent === node.item.code);
|
|
628
|
+
return hasChildren;
|
|
629
|
+
},
|
|
630
|
+
expendDepth: 1
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
locationTree.setData(locationData);
|
|
634
|
+
|
|
635
|
+
function handleLocationSelection(node) {
|
|
636
|
+
activeLocation = node.item;
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function isDirectory(node) {
|
|
641
|
+
return locationData.some(loc => loc.parent === node.item.code);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function getLocationIcon(type) {
|
|
645
|
+
switch (type) {
|
|
646
|
+
case 'country': return '🌍';
|
|
647
|
+
case 'province':
|
|
648
|
+
case 'state': return '🏛️';
|
|
649
|
+
case 'district':
|
|
650
|
+
case 'city': return '🏙️';
|
|
651
|
+
default: return '📍';
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function displayLocationName(item) {
|
|
656
|
+
return `${getLocationIcon(item.type)} ${item.name}`;
|
|
657
|
+
}
|
|
658
|
+
</script>
|
|
659
|
+
|
|
660
|
+
<div class="location-tree">
|
|
661
|
+
<h3>地理层级</h3>
|
|
662
|
+
<TreeView
|
|
663
|
+
nodes={locationTree.nodes}
|
|
664
|
+
textField={displayLocationName}
|
|
665
|
+
onchange={handleLocationSelection}
|
|
666
|
+
checkIsDirectory={isDirectory}
|
|
667
|
+
/>
|
|
668
|
+
|
|
669
|
+
{#if activeLocation}
|
|
670
|
+
<div class="location-details">
|
|
671
|
+
<h4>选中的位置</h4>
|
|
672
|
+
<p><strong>名称:</strong> {activeLocation.name}</p>
|
|
673
|
+
<p><strong>代码:</strong> {activeLocation.code}</p>
|
|
674
|
+
<p><strong>类型:</strong> {activeLocation.type}</p>
|
|
675
|
+
</div>
|
|
676
|
+
{/if}
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<style>
|
|
680
|
+
.location-tree {
|
|
681
|
+
width: 350px;
|
|
682
|
+
border: 1px solid #ddd;
|
|
683
|
+
border-radius: 4px;
|
|
684
|
+
padding: 16px;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.location-details {
|
|
688
|
+
margin-top: 16px;
|
|
689
|
+
padding: 12px;
|
|
690
|
+
background: #f8f9fa;
|
|
691
|
+
border-radius: 4px;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.location-details h4 {
|
|
695
|
+
margin: 0 0 8px 0;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.location-details p {
|
|
699
|
+
margin: 4px 0;
|
|
700
|
+
}
|
|
701
|
+
</style>
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
## 功能
|
|
705
|
+
|
|
706
|
+
- **层级显示**:清晰的树结构,支持可展开/折叠的节点
|
|
707
|
+
- **延迟加载**:按需加载子节点,适合大数据集
|
|
708
|
+
- **上下文菜单**:支持右键自定义操作
|
|
709
|
+
- **键盘导航**:完整的键盘可访问性支持
|
|
710
|
+
- **自定义可见性**:根据自定义标准过滤节点
|
|
711
|
+
- **选择管理**:跟踪和控制节点选择
|
|
712
|
+
- **事件处理**:全面的交互事件系统
|
|
713
|
+
- **灵活数据**:支持任何数据结构,配置灵活映射
|
|
714
|
+
|
|
715
|
+
## 节点管理
|
|
716
|
+
|
|
717
|
+
树视图组件与 `TreeNodes` 工具类配合使用,管理层级数据:
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
const treeNodes = new TreeNodes({
|
|
721
|
+
keyField: 'id', // 唯一标识字段
|
|
722
|
+
textField: 'name', // 显示文本字段
|
|
723
|
+
parentKeyField: 'parent', // 父节点引用字段
|
|
724
|
+
checkIsRoot: (item) => item.parent === null,
|
|
725
|
+
checkIsDirectory: (node) => node.children != null,
|
|
726
|
+
expendDepth: 1 // 初始展开深度
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
treeNodes.setData(flatData); // 将扁平数据转换为树结构
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
## 可访问性
|
|
733
|
+
|
|
734
|
+
- 支持使用箭头键和回车键进行键盘导航
|
|
735
|
+
- 提供适当的 ARIA 属性,兼容屏幕阅读器
|
|
736
|
+
- 焦点管理和视觉指示器
|
|
737
|
+
- 语义化 HTML 结构
|
|
738
|
+
- 支持 Tab 导航
|
|
739
|
+
|
|
740
|
+
## 最佳实践
|
|
741
|
+
|
|
742
|
+
1. **数据结构**:在数据中保持一致的字段名称
|
|
743
|
+
2. **性能**:为大数据集实现延迟加载
|
|
744
|
+
3. **可见性**:使用 `isVisible` 属性高效过滤节点
|
|
745
|
+
4. **选择**:在选择更改处理程序中始终返回布尔值
|
|
746
|
+
5. **上下文菜单**:提供上下文相关的菜单项
|
|
747
|
+
6. **可访问性**:确保适当的键盘导航支持
|
|
748
|
+
|
|
749
|
+
## 浏览器支持
|
|
750
|
+
|
|
751
|
+
- 支持完整事件处理的现代浏览器
|
|
752
|
+
- 兼容 Svelte 5+
|
|
753
|
+
- 支持键盘导航
|
|
754
|
+
- 触控友好界面
|
|
755
|
+
- 完整的 TypeScript 支持
|
|
756
|
+
|
|
757
|
+
## 相关组件
|
|
758
|
+
|
|
759
|
+
- `TreeNodes` - 树数据结构工具
|
|
760
|
+
- `ContextMenu` - 右键上下文菜单组件
|
|
761
|
+
- `LazyLoader` - 异步数据加载接口
|