@@ -22,7 +22,7 @@ yarn add he-tree-react
22
22
23
23
此库支持两种结构的数据:
24
24
25
- - 扁平数据, 即一个一维数组. 类似与存储在数据库中的数据. 每项需要` id ` , 父级 id, ` null ` 代表没有父级. 扁平数据的顺序必须准确, 你需要在初始化数据时使用 [ ` sortFlatData ` ] ( ./api#sortflatdata ) 方法给数据排序.
25
+ - 扁平数据, 即一个一维数组. 类似与存储在数据库中的数据. 每项需要` id ` , 父级 id, ` null ` 代表没有父级. 扁平数据的顺序必须跟树一样, 你可以在初始化数据时使用 [ ` sortFlatData ` ] ( ./api#sortflatdata ) 方法给数据排序.
26
26
``` js
27
27
[
28
28
{ id: 1 , pid: null },
@@ -51,7 +51,7 @@ yarn add he-tree-react
51
51
## 没有组件
52
52
53
53
此库没有导出组件,而是导出一个 hook ` useHeTree ` . 使用它返回的` renderHeTree ` 渲染树. 这样做的好处是除了` renderHeTree ` ,
54
- ` useHeTree ` 还会返回一些内部状态和方法, 可以轻松的被使用 .
54
+ ` useHeTree ` 还会返回一些内部状态和方法, 可以轻松的被获取 .
55
55
56
56
``` js
57
57
import { useHeTree } from " he-tree-react" ;
@@ -64,7 +64,29 @@ export default function App() {
64
64
}
65
65
```
66
66
67
- ## 基础使用-平面数据
67
+ ## 选项
68
+
69
+ ` useHeTree ` 是主要使用的函数, 它的第一个参数是选项对象. 必须的选项有` data ` , 必须两者中有一个的是` renderNode, renderNodeBox ` . 其他重要选项是:
70
+
71
+ - ` dataType ` , 表明数据类型. 可用值:
72
+ - ` flat ` , 默认. 扁平数据.
73
+ - ` tree ` , 树形数据.
74
+ - ` idKey, parentIdKey ` , 默认值是` id ` 和` parent_id ` . 使用扁平数据时需要. 虽然有默认值, 但还是建议写明更好.
75
+ - ` childrenKey ` , 默认是` children ` . 使用树形数据时需要. 虽然有默认值, 但还是建议写明更好.
76
+ - ` onChange ` , 数据改变时调用的函数, 参数是新数据. 如果你的树不会改变则不需要.
77
+ - ` isFunctionReactive ` , 布尔. 默认` false ` . ` useHeTree ` 选项中包含许多回调函数, 如` onChange, canDrop ` . ` isFunctionReactive ` 可用来控制是否监听这些回调函数的改变. 如果你的回调函数和` data ` 是同步改变的, 则不用启用此项. 否则你需要启用此项, 并且用 React 的` useCallback ` 或` useMemo ` 缓存你的所有回调函数以避免性能问题.
78
+
79
+ [ 查看` useHeTree ` 的 API 文档以了解更多] ( api#usehetree ) .
80
+
81
+ ## 提示
82
+
83
+ - ` stat ` , 单个节点的相关信息. 大部分回调函数的参数里有` stat ` . [ 参考` Stat ` API] ( api#stat ) .
84
+ - ` node ` , 节点的数据. 通过` stat.node ` 可以获取节点数据.
85
+ - ` getStat ` , 通过此函数可以获取` stat ` , 唯一参数可以是` id, node, stat ` . 此函数在` useHeTree ` 的返回对象中: ` const {getStat} = useHeTree({...}) ` .
86
+ - 下面的代码例子附带有运行效果. 这些例子可以直接复制使用. 注意其中的高亮行的代码.
87
+ - 下面的代码例子使用` tsx ` 格式, 如果你需要` js ` 格式, 可以使用任意 ts js 在线转换器.
88
+
89
+ ## 基础使用-扁平数据
68
90
69
91
<<< @/../src/pages/base_flat_data.tsx
70
92
<DemoIframe url =" /base_flat_data " />
@@ -73,3 +95,173 @@ export default function App() {
73
95
74
96
<<< @/../src/pages/base_tree_data.tsx
75
97
<DemoIframe url =" /base_tree_data " />
98
+
99
+ ## 自定义拖拽触发元素
100
+
101
+ 给节点任意子元素添加` draggable ` 属性即可.
102
+
103
+ <<< @/../src/pages/custom_drag_trigger_flat_data.tsx{14}
104
+ <DemoIframe url =" /custom_drag_trigger_flat_data " />
105
+
106
+ ## 节点 HTML 结构和样式
107
+
108
+ 节点 HTML 如下:
109
+
110
+ ``` html
111
+ <div
112
+ draggable =" true"
113
+ data-key =" 1"
114
+ data-level =" 1"
115
+ data-node-box =" true"
116
+ style =" padding-left : 0px ;"
117
+ >
118
+ <div >Node</div >
119
+ </div >
120
+ ```
121
+
122
+ 上面有两个 div. 使用` renderNode ` 选项控制内层 div 的渲染. 如: ` renderNode: ({node}) => <div>{node.name}</div> ` .
123
+
124
+ 外层节点被称为` nodeBox ` , 不要修改它的` margin, padding-left, padding-right ` , 不要给它的父元素设置` gap ` . 如果你想控制` nodeBox ` 或拖拽占位节点的渲染, 可以使用` renderNodeBox ` 选项, 这将覆盖` renderNode ` . 标准的` renderNodeBox ` 如下:
125
+
126
+ ``` tsx{4-7,9}
127
+ renderNodeBox: ({ stat, attrs, isPlaceholder }) => (
128
+ <div {...attrs}>
129
+ {isPlaceholder ? (
130
+ <div
131
+ className="he-tree-drag-placeholder"
132
+ style={{ minHeight: "20px", border: "1px dashed blue" }}
133
+ />
134
+ ) : (
135
+ <div>{/* node area */}</div>
136
+ )}
137
+ </div>
138
+ );
139
+ ```
140
+
141
+ 第 4 到第 7 行是拖拽占位节点. 第 9 行是节点元素.
142
+
143
+ ## 自定义拖拽占位节点和 node box
144
+
145
+ <<< @/../src/pages/customize_placeholder_and_node_box.tsx{13-19,23-39}
146
+ <DemoIframe url =" /customize_placeholder_and_node_box " />
147
+
148
+ ## 节点的展开与折叠
149
+
150
+ - 使用选项` openIds ` 表明展开的节点.
151
+ - 可通过` stat.open ` 获取该节点的` open ` 状态.
152
+ - ` useHeTree ` 返回的` allIds ` 包含所有节点的 id.
153
+ - 此库导出了方法可以展开单个或多个节点的所有父级. 扁平数据: [ ` openParentsInFlatData ` ] ( api#openparentsinflatdata ) . 树形数据: [ ` openParentsInTreeData ` ] ( api#openparentsintreedata ) .
154
+
155
+ <<< @/../src/pages/open_ids.tsx{1,9-16,22-24,29-32}
156
+ <DemoIframe url =" /open_ids " />
157
+ 此例子顶部 4 个按钮分别是: 展开全部, 折叠全部, 展开'Python'节点的所有父节点, 仅展开'Python'节点的所有父节点.
158
+
159
+ ## 节点的勾选
160
+
161
+ - 使用选项` checkedIds ` 表明勾选的节点.
162
+ - 可通过` stat.checked ` 获取该节点的` checked ` 状态.
163
+ - 此库导出了方法可以获取单个或多个节点` checked ` 变动后的` checkedIds ` . 扁平数据: [ ` updateCheckedInFlatData ` ] ( api#updatecheckedinflatdata ) . 树形数据: [ `updateCheckedInTreeData] ( api#updatecheckedintreedata ) .
164
+ - 此方法对节点的` checked ` 的更新是级联的. 如果你不想级联更新, 使用你自己的逻辑替代.
165
+ - 此方法返回一个长度 2 的数组. 第一项是所有勾选的 id, 第二项是所有半选的 id. 如果不需要半选, 忽略第二项.
166
+ - 半选, 即同时有子节点被勾选或半选, 也有子节点未被勾选.
167
+
168
+ <<< @/../src/pages/checked_ids.tsx{1,9-15,21-23,28-29}
169
+ <DemoIframe url =" /checked_ids " />
170
+
171
+ ## 控制是否可拖拽, 可放入
172
+
173
+ 使用以下选项控制:
174
+
175
+ - [ ` canDrag ` ] ( api#candrag ) , 节点是否可拖拽.
176
+ - [ ` canDrop ` ] ( api#candrop ) , 节点是否可放入.
177
+ - [ ` canDropToRoot ` ] ( api#candroptoroot ) , 树根是否可放入.
178
+
179
+ <<< @/../src/pages/draggable_droppable.tsx{16-18}
180
+ <DemoIframe url =" /draggable_droppable " />
181
+
182
+ - 根节点不可放入.
183
+ - ` Technology ` 及子节点可以拖拽. ` Science ` 及子节点不可以拖拽.
184
+ - ` Science ` 及子节点可以放入. ` Technology ` 及子节点不可以放入.
185
+
186
+ ## 拖拽到节点上时打开节点
187
+
188
+ 使用以下选项控制:
189
+
190
+ - [ ` dragOpen ` ] ( api#dragopen ) , 是否启用, 默认` false ` .
191
+ - [ ` dragOpenDelay ` ] ( api#dragopen ) , 延时, 默认 ` 600 ` 毫秒.
192
+ - [ ` onDragOpen ` ] ( api#ondragopen ) , 打开节点时调用的函数.
193
+
194
+ <<< @/../src/pages/dragopen.tsx
195
+ <DemoIframe url =" /dragopen " />
196
+
197
+ ## 更新数据
198
+
199
+ 由于 React 的不可变特性, 扁平数据和树形数据更新都很困难. 针对扁平数据, 此库提供了两个方法, 用以增加节点或删除节点. 如果你要进行更复杂的操作, 或者更新树形数据, 推荐你使用[ ` immer ` ] ( https://github.com/mweststrate/immer ) .
200
+ ::: code-group
201
+
202
+ ``` sh [npm]
203
+ npm install immer use-immer
204
+ ```
205
+
206
+ ``` sh [pnpm]
207
+ pnpm add immer use-immer
208
+ ```
209
+
210
+ ``` sh [yarn]
211
+ yarn add immer use-immer
212
+ ```
213
+
214
+ :::
215
+
216
+ ## 使用内置方法更新扁平数据
217
+
218
+ [ ` addToFlatData ` ] ( api#addtoflatdata ) : 增加节点. [ ` removeByIdInFlatData ` ] ( api#removebyidinflatdata ) : 删除节点.
219
+ 这两个方法都会改变原数据, 所以把原数据的复制传给它, 或者与` immer ` 一起使用.
220
+
221
+ <<< @/../src/pages/update_data.tsx{3,12-22,33-34}
222
+ <DemoIframe url =" /update_data " />
223
+
224
+ ## 使用 immer 更新扁平数据
225
+
226
+ 注意, 这里使用了` useImmer ` 替代 React 的` useState ` .
227
+
228
+ <<< @/../src/pages/update_flat_data_with_immer.tsx{3,7,12,13-31,42-44}
229
+ <DemoIframe url =" /update_flat_data_with_immer " />
230
+
231
+ ## 使用 immer 更新树形数据
232
+
233
+ 注意, 这里使用了` useImmer ` 替代 React 的` useState ` . ` findTreeData ` 方法类似数组的` find ` 方法.
234
+
235
+ <<< @/../src/pages/update_tree_data_with_immer.tsx{1,4,10-30,41-43}
236
+ <DemoIframe url =" /update_tree_data_with_immer " />
237
+
238
+ ## 从外部发起的拖拽
239
+
240
+ 相关选项:
241
+
242
+ - [ ` onExternalDragOver ` ] ( api#onexternaldragover ) : 表明是否处理外部拖拽.
243
+ - [ ` onExternalDrop ` ] ( api#onexternaldrop ) : 当外部拖拽放入树中时调用的回调函数.
244
+
245
+ <<< @/../src/pages/external_drag.tsx{16-22,25}
246
+ <DemoIframe url =" /external_drag " />
247
+
248
+ ## 超大数据
249
+
250
+ 使用选项[ ` virtual ` ] ( api#virtual ) 启用虚拟列表功能. 记得给树设置可见区域高度.
251
+
252
+ <<< @/../src/pages/virtual_list.tsx{23,30}
253
+ <DemoIframe url =" /virtual_list " />
254
+
255
+ ## 触摸 & 移动设备
256
+
257
+ 此库基于 HTML5 Drag and Drop API, 所以在支持 Drag and Drop API 的移动设备上能工作. 如果不支持, 可以尝试添加兼容 Drag and Drop API 的库.
258
+
259
+ ::: tip 注意
260
+ 触摸时, 用户需要触摸并等一会儿才能触发拖拽。
261
+ :::
262
+
263
+ ## 其他
264
+
265
+ - 选项 [ ` direction ` ] ( api#direction ) : 从右往左显示.
266
+ - 选项 [ ` customDragImage ` ] ( api#customdragimage ) : 自定义 drag image.
267
+ - 选项 [ ` rootId ` ] ( api#rootid ) : 使用扁平数据时, 顶级节点的父 id.
0 commit comments