oxy-uni-ui 1.1.0 → 1.2.3

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.
Files changed (123) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +59 -1
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +42 -0
  5. package/components/composables/index.ts +1 -0
  6. package/components/composables/useGlobalLoading.ts +42 -0
  7. package/components/composables/useGlobalMessage.ts +48 -0
  8. package/components/composables/useGlobalToast.ts +84 -0
  9. package/components/composables/useVirtualScroll.ts +173 -0
  10. package/components/oxy-cell/oxy-cell.vue +15 -2
  11. package/components/oxy-cell/types.ts +4 -0
  12. package/components/oxy-checkbox/index.scss +1 -1
  13. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  14. package/components/oxy-col-picker/oxy-col-picker.vue +3 -0
  15. package/components/oxy-col-picker/types.ts +5 -1
  16. package/components/oxy-corner/index.scss +121 -1
  17. package/components/oxy-corner/oxy-corner.vue +18 -5
  18. package/components/oxy-corner/types.ts +24 -3
  19. package/components/oxy-date-strip/index.scss +10 -0
  20. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  21. package/components/oxy-date-strip/types.ts +98 -0
  22. package/components/oxy-date-strip/utils.ts +67 -0
  23. package/components/oxy-date-strip-item/index.scss +94 -0
  24. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  25. package/components/oxy-date-strip-item/types.ts +53 -0
  26. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +3 -1
  27. package/components/oxy-datetime-picker/types.ts +5 -1
  28. package/components/oxy-echarts/index.scss +17 -0
  29. package/components/oxy-echarts/index.ts +1 -0
  30. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  31. package/components/oxy-echarts/types.ts +12 -0
  32. package/components/oxy-file-list/index.scss +26 -0
  33. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  34. package/components/oxy-file-list/types.ts +58 -2
  35. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  36. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  37. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  38. package/components/oxy-img-lazy/index.scss +17 -0
  39. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  40. package/components/oxy-img-lazy/types.ts +69 -0
  41. package/components/oxy-link/index.scss +57 -0
  42. package/components/oxy-link/oxy-link.vue +130 -0
  43. package/components/oxy-link/types.ts +81 -0
  44. package/components/oxy-list/index.scss +8 -1
  45. package/components/oxy-list/oxy-list.vue +121 -40
  46. package/components/oxy-list/types.ts +3 -15
  47. package/components/oxy-picker/oxy-picker.vue +3 -0
  48. package/components/oxy-picker/types.ts +5 -1
  49. package/components/oxy-radio/index.scss +3 -3
  50. package/components/oxy-radio/oxy-radio.vue +1 -1
  51. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  52. package/components/oxy-rich-text/icon/quote.svg +1 -0
  53. package/components/oxy-rich-text/icon/text.svg +1 -0
  54. package/components/oxy-rich-text/icon/title.svg +1 -0
  55. package/components/oxy-rich-text/index.scss +159 -0
  56. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  57. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  58. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  59. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  60. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  61. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  62. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  63. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  64. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  65. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  66. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  67. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  68. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  69. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  70. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  71. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  72. package/components/oxy-rich-text/mp-html/mp-html.vue +675 -0
  73. package/components/oxy-rich-text/mp-html/node/node.vue +1161 -0
  74. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  75. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  76. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  77. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  78. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  79. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  80. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  81. package/components/oxy-rich-text/types.ts +71 -0
  82. package/components/oxy-select/index.scss +255 -0
  83. package/components/oxy-select/oxy-select.vue +421 -0
  84. package/components/oxy-select/types.ts +71 -0
  85. package/components/oxy-select-picker/oxy-select-picker.vue +3 -0
  86. package/components/oxy-select-picker/types.ts +5 -1
  87. package/components/oxy-stream-render/index.scss +6 -0
  88. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  89. package/components/oxy-stream-render/types.ts +5 -0
  90. package/components/oxy-tree/index.scss +43 -5
  91. package/components/oxy-tree/oxy-tree.vue +233 -35
  92. package/components/oxy-tree/types.ts +54 -7
  93. package/components/oxy-tree/utils.ts +51 -0
  94. package/components/oxy-virtual-scroll/index.scss +1 -1
  95. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +69 -110
  96. package/components/oxy-virtual-scroll/types.ts +95 -5
  97. package/components/oxy-waterfall/index.scss +18 -0
  98. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  99. package/components/oxy-waterfall/types.ts +90 -0
  100. package/components/oxy-waterfall-item/index.scss +8 -0
  101. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  102. package/components/oxy-waterfall-item/types.ts +16 -0
  103. package/global.d.ts +7 -0
  104. package/index.ts +3 -0
  105. package/locale/lang/en-US.ts +35 -9
  106. package/locale/lang/zh-CN.ts +31 -5
  107. package/oxy-uni-ui.zip +0 -0
  108. package/package.json +1 -1
  109. package/tags.json +1 -1
  110. package/uni-echarts/changelog.md +2 -0
  111. package/uni-echarts/components/index.js +1 -0
  112. package/uni-echarts/components/uni-echarts/events.js +95 -0
  113. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  114. package/uni-echarts/components/uni-echarts/types.js +1 -0
  115. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  116. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  117. package/uni-echarts/global.d.ts +7 -0
  118. package/uni-echarts/index.d.ts +440 -0
  119. package/uni-echarts/index.js +2 -0
  120. package/uni-echarts/package.json +105 -0
  121. package/uni-echarts/shared-core.d.ts +269 -0
  122. package/uni-echarts/shared-core.js +900 -0
  123. package/web-types.json +1 -1
@@ -1,17 +1,56 @@
1
1
  <template>
2
2
  <view class="oxy-tree" :class="customClass" :style="customStyle">
3
- <oxy-virtual-scroll v-if="data.length" :data="flattenTree" :height="maxHeight" item-height="44px" :scrollX="true">
4
- <template #item="{ item }">
5
- <treeNodeContent :node="item" @toggle-expand="toggleExpand" @toggle-checked="toggleChecked" @click="handleClick">
6
- <template #default="{ node, data }">
7
- <slot :node="node" :data="data"></slot>
8
- </template>
9
- </treeNodeContent>
10
- </template>
11
- </oxy-virtual-scroll>
3
+ <slot name="search-button" v-if="showFilter">
4
+ <view class="oxy-tree__search">
5
+ <oxy-input
6
+ type="text"
7
+ no-border
8
+ class="oxy-tree__search-input"
9
+ prefix-icon="search"
10
+ :placeholder="filterPlaceholder"
11
+ v-model="searchValue"
12
+ @confirm="handleFilter"
13
+ />
14
+ <oxy-button :round="false" @click="handleFilter">筛选</oxy-button>
15
+ </view>
16
+ </slot>
17
+
18
+ <view v-if="data.length" class="oxy-tree__virtual-scroll" :style="{ height: height }">
19
+ <scroll-view class="oxy-tree__view" scroll-y :scroll-x="true" :scroll-top="scrollTop" @scroll="handleScroll">
20
+ <view class="oxy-tree__container" :style="{ height: totalHeight + 'px' }">
21
+ <view class="oxy-tree__items" :style="{ transform: `translateY(${virtualOffsetY}px)` }">
22
+ <view v-for="(item, index) in virtualData" :key="index">
23
+ <view class="oxy-tree-node-content" :style="getNodeStyle(item)" :class="getNodeClass(item)" @click="handleNodeClick(item)">
24
+ <!-- 兼容支付宝、微信小程序 -->
25
+ <view @tap.stop="handleClickExpand(item)">
26
+ <oxy-icon name="fill-arrow-down" custom-class="oxy-tree-node-icon" size="22px"></oxy-icon>
27
+ </view>
28
+ <oxy-checkbox
29
+ v-if="showCheckbox"
30
+ :modelValue="item.checked"
31
+ :disabled="item.disabled"
32
+ :indeterminate="item.immediate"
33
+ shape="square"
34
+ ></oxy-checkbox>
35
+ <view class="oxy-tree-node">
36
+ <slot name="node" :node="item" :data="item.data">
37
+ {{ item.label }}
38
+ </slot>
39
+ </view>
40
+ </view>
41
+ </view>
42
+ </view>
43
+ </view>
44
+ </scroll-view>
45
+ </view>
12
46
  <view v-else>
13
47
  <oxy-status-tip image="content" :tip="emptyText" />
14
48
  </view>
49
+
50
+ <!-- 回到顶部按钮 -->
51
+ <view v-if="showBackToTop && showBackTopBtn" class="oxy-virtual-scroll__back-top" @click="scrollToTop">
52
+ <oxy-icon name="backtop" color="#fff" size="20px"></oxy-icon>
53
+ </view>
15
54
  </view>
16
55
  </template>
17
56
 
@@ -27,23 +66,27 @@ export default {
27
66
  </script>
28
67
 
29
68
  <script lang="ts" setup>
30
- import { computed, nextTick, provide, ref, toRefs, watch } from 'vue'
31
- import type { RawTreeNode, TreeNode } from './types'
32
- import { textProps } from './types'
33
- import treeNodeContent from './components/tree-node-content.vue'
34
- import { isSetsEqual, useTreeMethods } from '.'
35
-
36
- // 树结构类型定义
37
- type Tree = {
38
- treeNodeMap: Map<string, TreeNode>
39
- levelTreeNodeMap: Map<number, TreeNode[]>
40
- maxLevel: number
41
- treeNodes: TreeNode[]
42
- }
69
+ import { computed, nextTick, provide, type Ref, ref, toRefs, watch } from 'vue'
70
+ import type { RawTreeNode, Tree, TreeInstance, TreeNode } from './types'
71
+ import { treeProps, type TreeExpose } from './types'
72
+ import { isSetsEqual, useTreeMethods } from './utils'
73
+ import { useVirtualScroll } from '../composables/useVirtualScroll'
43
74
 
44
75
  // 获取组件的 props 和 emit 函数
45
- const props = defineProps(textProps)
46
- const { modelValue, data, defaultExpandedKeys, expandAll, showCheckbox, checkStrictly, selectionLeafOnly } = toRefs(props)
76
+ const props = defineProps(treeProps)
77
+ const {
78
+ modelValue,
79
+ data,
80
+ defaultExpandedKeys,
81
+ expandAll,
82
+ showCheckbox,
83
+ checkStrictly,
84
+ selectionLeafOnly,
85
+ height,
86
+ itemHeight,
87
+ nodeKey,
88
+ backToTopThreshold
89
+ } = toRefs(props)
47
90
  const emit = defineEmits<{
48
91
  (e: 'node-click', node: TreeNode): void
49
92
  (e: 'update:modelValue', value: string[] | string | undefined): void
@@ -54,15 +97,13 @@ const emit = defineEmits<{
54
97
 
55
98
  const { getDisabled, getChildren, getLabel, getKey } = useTreeMethods(props)
56
99
  const expandedKeySet = ref<Set<string>>(new Set())
100
+ const bakExpandedKeySet = ref<Set<string> | null>(null)
57
101
  const hiddenNodeKeySet = ref<Set<string>>(new Set())
58
102
  const checkedKeys = ref<Set<string>>(new Set())
59
103
  const immediateKeySet = ref<Set<string>>(new Set())
60
104
  const currentNode = ref<TreeNode>()
61
- provide('treeProps', props)
62
- provide('currentNode', currentNode)
63
-
64
- const tree = ref<Tree>()
65
-
105
+ const searchValue = ref('')
106
+ const tree = ref<Tree>() as Ref<Tree>
66
107
  const flattenTree = computed<TreeNode[]>(() => {
67
108
  const expandedKeys = expandedKeySet.value
68
109
  const hiddenKeys = hiddenNodeKeySet.value
@@ -93,6 +134,32 @@ const flattenTree = computed<TreeNode[]>(() => {
93
134
  traverse()
94
135
  return flattenNodes
95
136
  })
137
+
138
+ // 虚拟滚动逻辑
139
+ const {
140
+ scrollTop,
141
+ showBackTopBtn,
142
+ virtualData,
143
+ startIndex,
144
+ virtualOffsetY,
145
+ totalHeight,
146
+ displayData,
147
+ updateVisibleData,
148
+ scrollToTop: virtualScrollToTop,
149
+ scrollToBottom: virtualScrollToBottom,
150
+ scrollToPosition: virtualScrollToPosition,
151
+ scrollToElement: virtualScrollToElement,
152
+ scrollToElementById: virtualScrollToElementById,
153
+ onScroll: handleVirtualScroll
154
+ } = useVirtualScroll({
155
+ data: flattenTree,
156
+ virtual: ref(true),
157
+ height: height,
158
+ itemHeight: itemHeight,
159
+ idKey: ref('key'),
160
+ backToTopThreshold: backToTopThreshold
161
+ })
162
+
96
163
  const createTree = (data: RawTreeNode[]) => {
97
164
  const treeNodeMap = new Map<string, TreeNode>()
98
165
  const levelTreeNodeMap = new Map<number, TreeNode[]>()
@@ -118,7 +185,6 @@ const createTree = (data: RawTreeNode[]) => {
118
185
  node.checked = checkedKeys.value.has(value)
119
186
  }
120
187
  if (expandAll.value) {
121
- node.expanded = true
122
188
  expandedKeySet.value.add(value)
123
189
  }
124
190
  const children = getChildren(rawNode)
@@ -151,9 +217,8 @@ const createTree = (data: RawTreeNode[]) => {
151
217
  }
152
218
 
153
219
  const toggleExpand = (node: TreeNode, flag: boolean) => {
154
- node.expanded = flag
155
220
  const key = node.key
156
- if (node.expanded) {
221
+ if (flag) {
157
222
  expandedKeySet.value.add(key)
158
223
  emit('node-expand', node)
159
224
  } else {
@@ -197,6 +262,11 @@ const handleClick = (node: TreeNode) => {
197
262
  updateValue()
198
263
  }
199
264
  }
265
+
266
+ // 滚动事件处理
267
+ const handleScroll = (event: any) => {
268
+ handleVirtualScroll(event.detail.scrollTop)
269
+ }
200
270
  const updateParentNode = (node: TreeNode) => {
201
271
  if (!node.parent) return
202
272
  updateNode(node.parent)
@@ -223,7 +293,6 @@ const updateNode = (node: TreeNode | undefined) => {
223
293
  const expandNode = (node: TreeNode | undefined) => {
224
294
  if (!node) return
225
295
  !node.isLeaf && expandedKeySet.value.add(node.key)
226
- node.expanded = true
227
296
  if (node.parent) {
228
297
  expandNode(node.parent)
229
298
  }
@@ -231,6 +300,12 @@ const expandNode = (node: TreeNode | undefined) => {
231
300
  const initValue = () => {
232
301
  if (showCheckbox.value) {
233
302
  if (isSetsEqual(checkedKeys.value, new Set(modelValue.value as string[]))) return
303
+ Array.from(checkedKeys.value).map((value) => {
304
+ const node = tree.value?.treeNodeMap.get(value as string)
305
+ if (node) {
306
+ toggleChecked(node, false)
307
+ }
308
+ })
234
309
  checkedKeys.value = new Set(modelValue.value as string[])
235
310
 
236
311
  Array.isArray(modelValue.value) &&
@@ -257,6 +332,30 @@ const updateValue = () => {
257
332
  emit('update:modelValue', currentNode.value?.key)
258
333
  }
259
334
  }
335
+ const getNodeStyle = (item: TreeNode) => {
336
+ return {
337
+ height: itemHeight.value,
338
+ paddingLeft: `${(item.level - 1) * (props.indent || 16)}px`
339
+ }
340
+ }
341
+ const getNodeClass = (item: TreeNode) => {
342
+ const currentValue = currentNode?.value
343
+ return {
344
+ expanded: expandedKeySet.value.has(item.key),
345
+ checked: item.checked,
346
+ 'is-leaf': item.isLeaf,
347
+ immediate: item.immediate,
348
+ 'is-current': currentValue === item,
349
+ 'is-disabled': item.disabled
350
+ }
351
+ }
352
+ const handleNodeClick = (item: TreeNode) => {
353
+ toggleChecked(item, !item.checked, true)
354
+ handleClick(item)
355
+ }
356
+ const handleClickExpand = (item: TreeNode) => {
357
+ toggleExpand(item, !expandedKeySet.value.has(item.key))
358
+ }
260
359
  watch(
261
360
  () => data.value,
262
361
  () => {
@@ -277,10 +376,109 @@ watch(
277
376
  initValue()
278
377
  }
279
378
  )
280
- defineExpose({
379
+ const getNodeById = (id: string | number) => {
380
+ return tree.value?.treeNodeMap.get(id as string)
381
+ }
382
+ const scrollToTop = () => {
383
+ virtualScrollToTop()
384
+ }
385
+ const scrollToBottom = () => {
386
+ const visibleCount = flattenTree.value.length
387
+ const containerHeight = parseFloat(height.value || '0')
388
+ const targetScrollTop = Math.max(visibleCount * parseFloat(itemHeight.value) - containerHeight, 0)
389
+ virtualScrollToPosition(targetScrollTop)
390
+ }
391
+ const scrollToPosition = (position: number | string) => {
392
+ virtualScrollToPosition(position)
393
+ }
394
+ const scrollToElement = (node: any) => {
395
+ expandNode(node)
396
+ nextTick(() => {
397
+ virtualScrollToElement(node)
398
+ })
399
+ }
400
+ const scrollToElementById = (id: string | number) => {
401
+ const targetNode = tree.value?.treeNodeMap.get(id as string)
402
+ if (targetNode) {
403
+ expandNode(targetNode)
404
+ nextTick(() => {
405
+ virtualScrollToElementById(id)
406
+ })
407
+ }
408
+ }
409
+ const getCheckedNodes = (): (TreeNode | any)[] => {
410
+ const checkNodes = Array.from(checkedKeys.value).map((key) => {
411
+ return tree.value?.treeNodeMap.get(key as string) || { [props.nodeKey]: key }
412
+ })
413
+ return checkNodes
414
+ }
415
+
416
+ const filter = (query: string) => {
417
+ if (bakExpandedKeySet.value === null) {
418
+ bakExpandedKeySet.value = new Set(expandedKeySet.value)
419
+ }
420
+ const keys = doFilter(query)
421
+ if (query && keys) {
422
+ expandedKeySet.value = keys
423
+ } else if (!query) {
424
+ bakExpandedKeySet.value && (expandedKeySet.value = new Set(bakExpandedKeySet.value))
425
+ bakExpandedKeySet.value = null
426
+ }
427
+ }
428
+
429
+ const doFilter = (query: string) => {
430
+ if (typeof props.filterMethod !== 'function') {
431
+ return
432
+ }
433
+ const expandKeySet = new Set<string>()
434
+ const hiddenKeys = hiddenNodeKeySet.value
435
+ const family: TreeNode[] = []
436
+ const nodes = tree.value.treeNodes || []
437
+ const filter = props.filterMethod
438
+ hiddenKeys.clear()
439
+ function traverse(nodes: TreeNode[]) {
440
+ nodes.forEach((node: TreeNode) => {
441
+ family.push(node)
442
+ if (filter(query, node.data)) {
443
+ family.forEach((member) => {
444
+ expandKeySet.add(member.key)
445
+ })
446
+ } else if (node.isLeaf) {
447
+ hiddenKeys.add(node.key)
448
+ }
449
+ const children = node.children
450
+ if (children) {
451
+ traverse(children)
452
+ }
453
+ if (!node.isLeaf) {
454
+ if (!expandKeySet.has(node.key)) {
455
+ hiddenKeys.add(node.key)
456
+ }
457
+ }
458
+ family.pop()
459
+ })
460
+ }
461
+ traverse(nodes)
462
+ return expandKeySet
463
+ }
464
+ const handleFilter = () => {
465
+ filter(searchValue.value)
466
+ }
467
+
468
+ defineExpose<TreeExpose>({
281
469
  toggleExpand,
282
470
  toggleChecked,
283
- tree
471
+ getNodeById,
472
+ getCheckedNodes,
473
+ getCurrentNode: () => currentNode.value,
474
+ useTree: () => tree.value,
475
+ getTree: () => tree,
476
+ scrollToTop,
477
+ scrollToBottom,
478
+ scrollToPosition,
479
+ scrollToElement,
480
+ scrollToElementById,
481
+ filter
284
482
  })
285
483
  </script>
286
484
 
@@ -1,6 +1,14 @@
1
- import type { ExtractPropTypes } from 'vue'
1
+ import type { ComponentPublicInstance, ExtractPropTypes, Ref } from 'vue'
2
2
  import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeNumericProp, makeStringProp } from '../common/props'
3
+ import { type PropType } from 'vue'
3
4
 
5
+ // 树结构类型定义
6
+ export type Tree = {
7
+ treeNodeMap: Map<string, TreeNode>
8
+ levelTreeNodeMap: Map<number, TreeNode[]>
9
+ maxLevel: number
10
+ treeNodes: TreeNode[]
11
+ }
4
12
  // 原始树节点类型
5
13
  export type RawTreeNode = {
6
14
  disabled?: boolean
@@ -25,13 +33,13 @@ export type TreeNode = {
25
33
  isCurrent?: boolean
26
34
  }
27
35
 
28
- export const textProps = {
36
+ export const treeProps = {
29
37
  ...baseProps,
30
38
  data: makeArrayProp<RawTreeNode>(),
31
39
  showCheckbox: makeBooleanProp(false),
32
40
  childrenKey: makeStringProp('children'),
33
41
  labelKey: makeStringProp('name'),
34
- valueKey: makeStringProp('id'),
42
+ nodeKey: makeStringProp('id'),
35
43
  defaultExpandedKeys: makeArrayProp<string>(),
36
44
  expandAll: makeBooleanProp(false),
37
45
  checkStrictly: makeBooleanProp(false),
@@ -40,9 +48,48 @@ export const textProps = {
40
48
  default: ''
41
49
  },
42
50
  emptyText: makeStringProp('暂无数据'),
43
- maxHeight: makeStringProp('300px'),
51
+ height: makeStringProp('300px'),
52
+ /**
53
+ * 是否显示回到顶部按钮
54
+ * 类型:boolean
55
+ * 默认值:false
56
+ */
57
+ showBackToTop: makeBooleanProp(false),
58
+ /**
59
+ * 滚动多远显示backToTop
60
+ * 类型:number
61
+ * 默认值:'300px'
62
+ */
63
+ backToTopThreshold: makeStringProp('300px'),
64
+ /**
65
+ * 单个项目高度
66
+ * 类型:number
67
+ * 默认值:'44px'
68
+ */
69
+ itemHeight: makeStringProp('44px'),
44
70
  indent: makeNumberProp(16),
45
- selectionLeafOnly: makeBooleanProp(false)
71
+ selectionLeafOnly: makeBooleanProp(false),
72
+ filterMethod: {
73
+ type: Function as PropType<(keyword: string, node: RawTreeNode) => boolean>,
74
+ default: null
75
+ },
76
+ showFilter: makeBooleanProp(false),
77
+ filterPlaceholder: makeStringProp('请输入节点名称')
46
78
  }
47
-
48
- export type TextProps = ExtractPropTypes<typeof textProps>
79
+ export type TreeExpose = {
80
+ toggleExpand: (node: TreeNode, flag: boolean) => void
81
+ toggleChecked: (node: TreeNode, flag: boolean, isClick: boolean) => void
82
+ getNodeById: (id: string | number) => TreeNode | undefined
83
+ getCheckedNodes: () => TreeNode[] | any
84
+ getCurrentNode: () => TreeNode | undefined
85
+ useTree: () => Tree
86
+ getTree: () => Ref<Tree>
87
+ scrollToTop: () => void
88
+ scrollToBottom: () => void
89
+ scrollToPosition: (position: number | string) => void
90
+ scrollToElement: (item: any) => void
91
+ scrollToElementById: (id: string | number) => void
92
+ filter: (keyword: string) => void
93
+ }
94
+ export type TreeProps = ExtractPropTypes<typeof treeProps>
95
+ export type TreeInstance = ComponentPublicInstance<TreeProps, TreeExpose>
@@ -0,0 +1,51 @@
1
+ import type { RawTreeNode, TreeProps } from './types'
2
+
3
+ export const useTreeMethods = (props: TreeProps) => {
4
+ function getDisabled(node: RawTreeNode): boolean {
5
+ return node.disabled ?? false
6
+ }
7
+
8
+ function getChildren(node: RawTreeNode): RawTreeNode[] {
9
+ return node[props.childrenKey] ?? []
10
+ }
11
+
12
+ function getLabel(node: RawTreeNode): string {
13
+ return node[props.labelKey] ?? ''
14
+ }
15
+
16
+ function getKey(node: RawTreeNode | undefined): string {
17
+ if (!node) {
18
+ return ''
19
+ }
20
+ return (node[props.nodeKey] ?? '') as string
21
+ }
22
+
23
+ return {
24
+ getDisabled,
25
+ getChildren,
26
+ getLabel,
27
+ getKey
28
+ }
29
+ }
30
+ /**
31
+ * 判断两个 Set 中的元素是否完全相同(不考虑顺序)
32
+ * @param {Set} setA - 第一个 Set
33
+ * @param {Set} setB - 第二个 Set
34
+ * @returns {boolean} 两个 Set 是否相同
35
+ */
36
+ export function isSetsEqual(setA: Set<any>, setB: Set<any>) {
37
+ // 步骤1:如果大小不同,直接返回 false
38
+ if (setA.size !== setB.size) {
39
+ return false
40
+ }
41
+
42
+ // 步骤2:遍历 setA 的所有元素,检查 setB 是否都包含
43
+ for (const item of setA) {
44
+ if (!setB.has(item)) {
45
+ return false // 有元素不匹配,返回 false
46
+ }
47
+ }
48
+
49
+ // 所有元素匹配,返回 true
50
+ return true
51
+ }
@@ -3,10 +3,10 @@
3
3
  @include b(virtual-scroll) {
4
4
  position: relative;
5
5
  width: 100%;
6
+ height: 100%;
6
7
 
7
8
  @include e(view) {
8
9
  width: 100%;
9
- height: 100%;
10
10
  }
11
11
  @include e(container) {
12
12
  position: relative;