From ae21389768eef66986bed10c4f3ab7bf07953a6f Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 15:30:27 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor(tree):=20=E9=87=8D=E6=9E=84tree?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=EF=BC=8C=E4=BD=BF=E7=94=A8=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8C=96=E7=9A=84useTree=E4=BD=9C=E4=B8=BA=E5=BA=95=E5=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devui-vue/devui/tree/index.ts | 4 +- .../tree/src/components/tree-node-toggle.tsx | 25 ++++--- packages/devui-vue/devui/tree/src/const.ts | 1 + .../devui/tree/src/core/tree-factory-types.ts | 3 +- .../devui-vue/devui/tree/src/core/use-core.ts | 26 +++++++- .../devui-vue/devui/tree/src/core/use-tree.ts | 1 + .../devui-vue/devui/tree/src/new-tree.tsx | 46 +++++++++++++ .../devui-vue/docs/components/tree/index.md | 65 +++++++++++++++++++ 8 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 packages/devui-vue/devui/tree/src/const.ts create mode 100644 packages/devui-vue/devui/tree/src/new-tree.tsx diff --git a/packages/devui-vue/devui/tree/index.ts b/packages/devui-vue/devui/tree/index.ts index 401ecd92ae..4acbba1e26 100644 --- a/packages/devui-vue/devui/tree/index.ts +++ b/packages/devui-vue/devui/tree/index.ts @@ -1,9 +1,10 @@ import type { App } from 'vue'; import Tree from './src/tree'; +import NewTree from './src/new-tree'; export * from './src/tree-types'; -export { Tree }; +export { Tree, NewTree }; export default { title: 'Tree 树', @@ -11,5 +12,6 @@ export default { status: '20%', install(app: App): void { app.component(Tree.name, Tree); + app.component(NewTree.name, NewTree); } }; diff --git a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx index e170d0f5dd..a11f1d62d4 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx @@ -1,4 +1,5 @@ -import { defineComponent, PropType, toRefs } from 'vue'; +import { defineComponent, inject, PropType, toRefs } from 'vue'; +import { USE_TREE_TOKEN } from '../const'; import { ITreeNode } from '../core/tree-factory-types'; import { IconClose } from './icon-close'; import { IconOpen } from './icon-open'; @@ -12,17 +13,23 @@ export default defineComponent({ }, setup(props) { const { data } = toRefs(props); + const treeFactory = inject(USE_TREE_TOKEN); + const { toggleNode } = treeFactory; return () => { return ( - - {data.value.isLeaf ? ( - - ) : data.value.expanded ? ( - - ) : ( - - )} + { + toggleNode(data.value); + }}> + { + data.value.isLeaf + ? + : data.value.expanded + ? + : + } ); }; diff --git a/packages/devui-vue/devui/tree/src/const.ts b/packages/devui-vue/devui/tree/src/const.ts new file mode 100644 index 0000000000..e9524aaee0 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/const.ts @@ -0,0 +1 @@ +export const USE_TREE_TOKEN = 'use-tree-token'; diff --git a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts index a031c778d1..ea2dc47ae3 100644 --- a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts +++ b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts @@ -1,4 +1,4 @@ -import { Ref } from 'vue'; +import { ComputedRef, Ref } from 'vue'; // 外部数据结构先只考虑嵌套结构 export interface ITreeNode { @@ -28,6 +28,7 @@ export type valueof = T[keyof T]; export interface IUseCore { getLevel: (node: ITreeNode) => number; getChildren: (node: ITreeNode) => IInnerTreeNode[]; + getExpendedTree: () => ComputedRef; getIndex: (node: ITreeNode) => number; getNode: (node: ITreeNode) => IInnerTreeNode; setNodeValue: (node: IInnerTreeNode, key: keyof IInnerTreeNode, value: valueof) => void; diff --git a/packages/devui-vue/devui/tree/src/core/use-core.ts b/packages/devui-vue/devui/tree/src/core/use-core.ts index 23270d6a21..77b5d87f31 100644 --- a/packages/devui-vue/devui/tree/src/core/use-core.ts +++ b/packages/devui-vue/devui/tree/src/core/use-core.ts @@ -1,4 +1,4 @@ -import { Ref } from 'vue'; +import { computed, ComputedRef, Ref } from 'vue'; import { IInnerTreeNode, ITreeNode, IUseCore, valueof } from './tree-factory-types'; import { generateInnerTree } from './utils'; @@ -21,6 +21,29 @@ export default function useCore(data: Ref): IUseCore { return result; } + const getExpendedTree = (): ComputedRef => { + return computed(() => { + let excludeNodes = []; + let result = []; + + for (let i = 0, len = data?.value.length; i < len; i++) { + const item = data?.value[i]; + + if (excludeNodes.map(node => node.id).includes(item.id)) { + continue; + } + + if (item.expanded !== true) { + excludeNodes = getChildren(item); + } + + result.push(item); + } + + return result; + }); + } + const getIndex = (node: ITreeNode): number => { return data.value.findIndex((item) => item.id === node.id); } @@ -40,6 +63,7 @@ export default function useCore(data: Ref): IUseCore { return { getLevel, getChildren, + getExpendedTree, getIndex, getNode, setNodeValue, diff --git a/packages/devui-vue/devui/tree/src/core/use-tree.ts b/packages/devui-vue/devui/tree/src/core/use-tree.ts index 44f6d70960..b737c77723 100644 --- a/packages/devui-vue/devui/tree/src/core/use-tree.ts +++ b/packages/devui-vue/devui/tree/src/core/use-tree.ts @@ -9,6 +9,7 @@ export const DEFAULT_TREE_PLUGINS = [useCore, useToggle]; export default function useTree(tree: ITreeNode[], plugins = []): Partial { const treeData = ref(generateInnerTree(tree)); + // TODO: useCore会在useTree是执行两次的问题待解决 const core: IUseCore = useCore(treeData); const pluginMethods = DEFAULT_TREE_PLUGINS.concat(plugins).reduce((acc, plugin) => { diff --git a/packages/devui-vue/devui/tree/src/new-tree.tsx b/packages/devui-vue/devui/tree/src/new-tree.tsx new file mode 100644 index 0000000000..8d283aa211 --- /dev/null +++ b/packages/devui-vue/devui/tree/src/new-tree.tsx @@ -0,0 +1,46 @@ +import { defineComponent, PropType, provide, toRefs, watch } from 'vue'; +import type { ITreeNode } from './core/tree-factory-types'; +import DTreeNode from './components/tree-node'; +import useTree from './core/use-tree'; +import useCheck from './core/use-check'; +import useSelect from './core/use-select'; +import { USE_TREE_TOKEN } from './const'; +import './tree.scss'; + +export default defineComponent({ + name: 'DNewTree', + props: { + data: { + type: Object as PropType, + default: [] + } + }, + setup(props) { + const { data } = toRefs(props); + + const treeFactory = useTree( + data.value, + [useSelect, useCheck] + ); + + const { + setTree, + getExpendedTree, + } = treeFactory; + + // 外部同步内部 + watch(data, setTree); + + provide(USE_TREE_TOKEN, treeFactory); + + return () => { + return ( +
+ { + getExpendedTree().value.map(treeNode => ) + } +
+ ); + } + } +}); diff --git a/packages/devui-vue/docs/components/tree/index.md b/packages/devui-vue/docs/components/tree/index.md index 69458a1808..773ac3e5b4 100644 --- a/packages/devui-vue/docs/components/tree/index.md +++ b/packages/devui-vue/docs/components/tree/index.md @@ -6,6 +6,8 @@ 文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。 +### 基本用法 + :::demo ```vue @@ -1028,3 +1030,66 @@ export default defineComponent({ ``` ::: + +### NewTree + +:::demo + +```vue + + +``` + +::: From d5a307b6718013cd631989efcaa0c67797b48e52 Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 16:15:47 +0800 Subject: [PATCH 2/6] feat(tree): add selectNode --- .../devui/tree/src/components/tree-node-toggle.tsx | 3 +-- .../devui-vue/devui/tree/src/components/tree-node.tsx | 8 ++++++-- packages/devui-vue/devui/tree/src/core/use-select.ts | 11 ++++++++++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx index a11f1d62d4..43e6dfacaa 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx @@ -13,8 +13,7 @@ export default defineComponent({ }, setup(props) { const { data } = toRefs(props); - const treeFactory = inject(USE_TREE_TOKEN); - const { toggleNode } = treeFactory; + const { toggleNode } = inject(USE_TREE_TOKEN); return () => { return ( diff --git a/packages/devui-vue/devui/tree/src/components/tree-node.tsx b/packages/devui-vue/devui/tree/src/components/tree-node.tsx index 26c472deb7..a1d04c4f3c 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node.tsx @@ -1,4 +1,5 @@ -import { defineComponent, PropType, ref, toRefs } from 'vue'; +import { defineComponent, inject, PropType, ref, toRefs } from 'vue'; +import { USE_TREE_TOKEN } from '../const'; import { ITreeNode } from '../core/tree-factory-types'; import DTreeNodeToggle from './tree-node-toggle'; @@ -11,13 +12,16 @@ export default defineComponent({ }, setup(props) { const { data } = toRefs(props); + const { selectNode } = inject(USE_TREE_TOKEN); return () => { return (
-
+
{ + selectNode(data.value); + }}>
{data.value.label} diff --git a/packages/devui-vue/devui/tree/src/core/use-select.ts b/packages/devui-vue/devui/tree/src/core/use-select.ts index de74b38ee9..2f046a4af7 100644 --- a/packages/devui-vue/devui/tree/src/core/use-select.ts +++ b/packages/devui-vue/devui/tree/src/core/use-select.ts @@ -1,4 +1,4 @@ -import { Ref } from 'vue'; +import { ref, Ref } from 'vue'; import { IInnerTreeNode, IUseCore } from './tree-factory-types'; export default function useSelect(data: Ref, core: IUseCore) { @@ -6,8 +6,17 @@ export default function useSelect(data: Ref, core: IUseCore) { const { setNodeValue } = core; + let prevActiveNode: IInnerTreeNode; + const selectNode = (node: IInnerTreeNode): void => { + if (node.disableSelect) { return; } + if (node.id === prevActiveNode?.id) { return; } + if (prevActiveNode) { + const prevActiveNodeIndex = data.value.findIndex(item => item.id === prevActiveNode.id) + setNodeValue(data.value[prevActiveNodeIndex], 'selected', false); + } setNodeValue(node, 'selected', true); + prevActiveNode = node; } return { From 22ef7addbae2f97bffafbe7ed92e4778c508ff00 Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 16:33:32 +0800 Subject: [PATCH 3/6] feat(tree): add useCheck --- .../devui-vue/devui/tree/src/components/tree-node.tsx | 8 ++++++-- .../devui/tree/src/core/tree-factory-types.ts | 1 + packages/devui-vue/devui/tree/src/core/use-check.ts | 11 ++++++++++- packages/devui-vue/devui/tree/src/core/use-toggle.ts | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/devui-vue/devui/tree/src/components/tree-node.tsx b/packages/devui-vue/devui/tree/src/components/tree-node.tsx index a1d04c4f3c..2a7bd84e86 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node.tsx @@ -2,6 +2,7 @@ import { defineComponent, inject, PropType, ref, toRefs } from 'vue'; import { USE_TREE_TOKEN } from '../const'; import { ITreeNode } from '../core/tree-factory-types'; import DTreeNodeToggle from './tree-node-toggle'; +import { Checkbox } from '../../../checkbox'; export default defineComponent({ name: 'DTreeNode', @@ -12,7 +13,7 @@ export default defineComponent({ }, setup(props) { const { data } = toRefs(props); - const { selectNode } = inject(USE_TREE_TOKEN); + const { selectNode, toggleCheckNode } = inject(USE_TREE_TOKEN); return () => { return ( @@ -22,8 +23,11 @@ export default defineComponent({
{ selectNode(data.value); }}> +
- + { { + toggleCheckNode(data.value); + }} /> } {data.value.label}
diff --git a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts index ea2dc47ae3..f5b9ccb95c 100644 --- a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts +++ b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts @@ -38,6 +38,7 @@ export interface IUseCore { export interface IUseCheck { checkNode: (node: IInnerTreeNode) => void; uncheckNode: (node: IInnerTreeNode) => void; + toggleCheckNode: (node: IInnerTreeNode) => void; } export interface IUseDisable { diff --git a/packages/devui-vue/devui/tree/src/core/use-check.ts b/packages/devui-vue/devui/tree/src/core/use-check.ts index 6650683eda..b5999182d0 100644 --- a/packages/devui-vue/devui/tree/src/core/use-check.ts +++ b/packages/devui-vue/devui/tree/src/core/use-check.ts @@ -4,7 +4,7 @@ import { IInnerTreeNode, IUseCore } from './tree-factory-types'; export default function useCheck(data: Ref, core: IUseCore) { console.log('useCheck:', data, data.value); - const { setNodeValue } = core; + const { setNodeValue, getNode } = core; const checkNode = (node: IInnerTreeNode): void => { setNodeValue(node, 'checked', true); @@ -14,8 +14,17 @@ export default function useCheck(data: Ref, core: IUseCore) { setNodeValue(node, 'checked', false); } + const toggleCheckNode = (node: IInnerTreeNode): void => { + if (getNode(node).checked) { + setNodeValue(node, 'checked', false); + } else { + setNodeValue(node, 'checked', true); + } + } + return { checkNode, uncheckNode, + toggleCheckNode, } } \ No newline at end of file diff --git a/packages/devui-vue/devui/tree/src/core/use-toggle.ts b/packages/devui-vue/devui/tree/src/core/use-toggle.ts index 42a78b8f26..cebf7aa1d0 100644 --- a/packages/devui-vue/devui/tree/src/core/use-toggle.ts +++ b/packages/devui-vue/devui/tree/src/core/use-toggle.ts @@ -6,15 +6,15 @@ export default function useToggle(data: Ref, core: IUseCore) { const { getNode, setNodeValue } = core; - const expandNode = (node: ITreeNode): void => { + const expandNode = (node: IInnerTreeNode): void => { setNodeValue(node, 'expanded', true); } - const collapseNode = (node: ITreeNode): void => { + const collapseNode = (node: IInnerTreeNode): void => { setNodeValue(node, 'expanded', false); } - const toggleNode = (node: ITreeNode): void => { + const toggleNode = (node: IInnerTreeNode): void => { console.log('toggleNode node:', node); if (getNode(node).expanded) { From 20583423b9cd129adcf7651269fb58170b2fc7ce Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 16:40:53 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix(tree):=20=E8=A7=A3=E5=86=B3=E5=8B=BE?= =?UTF-8?q?=E9=80=89=E4=B9=8B=E5=90=8E=E8=8A=82=E7=82=B9=E9=AB=98=E4=BA=AE?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui-vue/devui/tree/src/components/tree-node-toggle.tsx | 3 ++- packages/devui-vue/devui/tree/src/components/tree-node.tsx | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx index 43e6dfacaa..60ba0c2290 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx @@ -19,7 +19,8 @@ export default defineComponent({ return ( { + onClick={(event: MouseEvent) => { + event.stopPropagation(); toggleNode(data.value); }}> { diff --git a/packages/devui-vue/devui/tree/src/components/tree-node.tsx b/packages/devui-vue/devui/tree/src/components/tree-node.tsx index 2a7bd84e86..ef11b64b4f 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node.tsx @@ -27,6 +27,8 @@ export default defineComponent({
{ { toggleCheckNode(data.value); + }} onClick={(event: MouseEvent) => { + event.stopPropagation(); }} /> } {data.value.label}
From 0d7c92c9b286096c3e6bd670e72ccdbd3b7369da Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 17:42:48 +0800 Subject: [PATCH 5/6] feat(tree): add useDisable --- .../tree/src/components/tree-node-toggle.tsx | 2 +- .../devui/tree/src/components/tree-node.tsx | 14 +-- .../devui-vue/devui/tree/src/core/README.md | 81 +++++++++++---- .../devui/tree/src/core/tree-factory-types.ts | 3 + .../devui/tree/src/core/tree-factory.ts | 99 ------------------- .../devui/tree/src/core/use-check.ts | 2 - .../devui-vue/devui/tree/src/core/use-core.ts | 3 +- .../devui/tree/src/core/use-disable.ts | 15 +++ .../devui/tree/src/core/use-operate.ts | 2 +- .../devui/tree/src/core/use-select.ts | 5 +- .../devui/tree/src/core/use-toggle.ts | 10 +- .../devui-vue/docs/components/tree/index.md | 5 +- 12 files changed, 102 insertions(+), 139 deletions(-) delete mode 100644 packages/devui-vue/devui/tree/src/core/tree-factory.ts diff --git a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx index 60ba0c2290..632b5790b8 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx @@ -18,7 +18,7 @@ export default defineComponent({ return () => { return ( { event.stopPropagation(); toggleNode(data.value); diff --git a/packages/devui-vue/devui/tree/src/components/tree-node.tsx b/packages/devui-vue/devui/tree/src/components/tree-node.tsx index ef11b64b4f..a63decb0e7 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node.tsx @@ -1,6 +1,6 @@ -import { defineComponent, inject, PropType, ref, toRefs } from 'vue'; +import { defineComponent, inject, PropType, toRefs } from 'vue'; import { USE_TREE_TOKEN } from '../const'; -import { ITreeNode } from '../core/tree-factory-types'; +import { IInnerTreeNode } from '../core/tree-factory-types'; import DTreeNodeToggle from './tree-node-toggle'; import { Checkbox } from '../../../checkbox'; @@ -8,7 +8,7 @@ export default defineComponent({ name: 'DTreeNode', props: { data: { - type: Object as PropType, + type: Object as PropType, }, }, setup(props) { @@ -18,19 +18,19 @@ export default defineComponent({ return () => { return (
+ class={['devui-tree-node', data.value?.expanded && 'devui-tree-node__open']} + style={{ paddingLeft: `${24 * (data.value?.level - 1)}px` }}>
{ selectNode(data.value); }}>
- { { + { { toggleCheckNode(data.value); }} onClick={(event: MouseEvent) => { event.stopPropagation(); }} /> } - {data.value.label} + {data.value?.label}
diff --git a/packages/devui-vue/devui/tree/src/core/README.md b/packages/devui-vue/devui/tree/src/core/README.md index f27589db9f..a90993dba3 100644 --- a/packages/devui-vue/devui/tree/src/core/README.md +++ b/packages/devui-vue/devui/tree/src/core/README.md @@ -1,4 +1,4 @@ -# Tree Factory +# useTree Tree 组件最核心的部分,是 UI 无关的,用于树形结构的处理。 @@ -6,13 +6,13 @@ Tree 组件最核心的部分,是 UI 无关的,用于树形结构的处理 - 获取子节点 - 搜索节点 - 插入 / 移除 / 编辑节点 -- 点选 / 勾选 / 展开收起节点 -- 点选 / 勾选 / 展开收起节点功能的禁用 +- 点击选择 / 勾选 / 展开收起节点 +- 点击选择 / 勾选 / 展开收起节点功能的禁用 ## 快速开始 ```ts -const treeData = [ +const data = [ { label: 'Parent node 1', children: [ @@ -22,30 +22,71 @@ const treeData = [ { label: 'Leaf node 2' } ]; -const treeFactory = new TreeFactory(treeData); -treeFactory.getTree(); +const { getExpendedTree } = useTree(data, [useSelect, useCheck]); ``` ## API +`useTree`支持插件化,每个功能都是一个插件,内置`useCore`/`useToggle`两个插件,其他插件可以手动引入,未引入的插件代码不会执行,也不会包含在构建产物里。 + +插件: +- useCore 核心插件(内置) +- useToggle 展开收起(内置) +- useSelect 点击选择 +- useCheck 勾选 +- useDisable 禁用 +- useOperate 节点操作 + +### useCore + | 名称 | 描述 | | -- | -- | -| getTree() => ITreeNode[] | 获取整棵树 | | setTree(tree: ITreeNode[]) => void | 设置整棵树 | | getLevel(node: ITreeNode) => number | 获取节点层级 | -| getChildren(node: ITreeNode): ITreeNode[] | 获取子节点 | -| selectNode(node: ITreeNode): void | 点击选择 | -| checkNode(node: ITreeNode): void | 勾选 | -| uncheckNode(node: ITreeNode): void | 取消勾选 | -| expandNode(node: ITreeNode): void | 展开 | -| collapseNode(node: ITreeNode): void | 收起 | -| toggleNode(node: ITreeNode): void | 切换展开/收起状态 | -| disableSelectNode(node: ITreeNode): void | 禁用点击选择 | -| disableCheckNode(node: ITreeNode): void | 禁用勾选 | -| disableToggleNode(node: ITreeNode): void | 禁用展开/收起 | -| insertBefore(parentNode: ITreeNode, node: ITreeNode, referenceNode: ITreeNode, cut: boolean = false): void | 插入节点 | -| removeNode(node: ITreeNode): void | 移除节点 | -| editNode(node: ITreeNode, label: string): void | 编辑节点内容 | +| getChildren(node: ITreeNode) => ITreeNode[] | 获取子节点 | +| getExpendedTree() => ComputedRef | 获取展开的树 | +| getIndex(node: ITreeNode) => number | 获取节点的 index | +| getNode(node: ITreeNode) => IInnerTreeNode | 获取节点数据 | +| setNodeValue(node: IInnerTreeNode, key: keyof IInnerTreeNode, value: valueof) => void | 设置节点属性 | + +### useSelect + +| 名称 | 描述 | +| -- | -- | +| selectNode(node: ITreeNode) => void | 点击选择 | + +### useCheck + +| 名称 | 描述 | +| -- | -- | +| checkNode(node: ITreeNode) => void | 勾选 | +| uncheckNode(node: ITreeNode) => void | 取消勾选 | +| toggleCheckNode(node: ITreeNode) => void | 取消勾选状态 | + +### useToggle + +| 名称 | 描述 | +| -- | -- | +| expandNode(node: ITreeNode) => void | 展开 | +| collapseNode(node: ITreeNode) => void | 收起 | +| toggleNode(node: ITreeNode) => void | 切换展开/收起状态 | + +### useDisable + +| 名称 | 描述 | +| -- | -- | +| disableSelectNode(node: ITreeNode) => void | 禁用点击选择 | +| disableCheckNode(node: ITreeNode) => void | 禁用勾选 | +| disableToggleNode(node: ITreeNode) => void | 禁用展开/收起 | +| enableSelectNode(node: ITreeNode) => void | 取消禁用点击选择 | +| enableCheckNode(node: ITreeNode) => void | 取消禁用勾选 | +| enableToggleNode(node: ITreeNode) => void | 取消禁用展开/收起 | + +### useOperate + +| insertBefore(parentNode: ITreeNode, node: ITreeNode, referenceNode: ITreeNode, cut: boolean = false) => void | 插入节点 | +| removeNode(node: ITreeNode) => void | 移除节点 | +| editNode(node: ITreeNode, label: string) => void | 编辑节点内容 | ## ITreeNode diff --git a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts index f5b9ccb95c..76657458d5 100644 --- a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts +++ b/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts @@ -45,6 +45,9 @@ export interface IUseDisable { disableSelectNode: (node: IInnerTreeNode) => void; disableCheckNode: (node: IInnerTreeNode) => void; disableToggleNode: (node: IInnerTreeNode) => void; + enableSelectNode: (node: IInnerTreeNode) => void; + enableCheckNode: (node: IInnerTreeNode) => void; + enableToggleNode: (node: IInnerTreeNode) => void; } export interface IUseOperate { diff --git a/packages/devui-vue/devui/tree/src/core/tree-factory.ts b/packages/devui-vue/devui/tree/src/core/tree-factory.ts deleted file mode 100644 index 8fe062afea..0000000000 --- a/packages/devui-vue/devui/tree/src/core/tree-factory.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { IInnerTreeNode, ITreeNode } from './tree-factory-types'; -import { flatToNested, generateInnerTree } from './utils'; - -export default class TreeFactory { - private _innerTree: IInnerTreeNode[] = []; - - private _getIndex(node: ITreeNode): number { - return this._innerTree.findIndex((item) => item.id === node.id); - } - - private _setNodeValue(node, key, value): void { - this._innerTree[this._getIndex(node)][key] = value; - } - - constructor(tree: ITreeNode[]) { - this.setTree(tree); - } - - getTree(flat?: boolean = true): IInnerTreeNode[] { - if (flat) { - return this._innerTree; - } else { - // TODO: 移除内部属性(level / parentId / idType) / 内部生成的id / 空children - return flatToNested(this._innerTree); - } - } - - setTree(tree: ITreeNode[]) { - this._innerTree = generateInnerTree(tree); - } - - getLevel(node: ITreeNode): number { - return this._innerTree.find((item) => item.id === node.id).level; - } - - getChildren(node: ITreeNode): IInnerTreeNode[] { - let result = []; - const startIndex = this._innerTree.findIndex((item) => item.id === node.id); - - for (let i = startIndex + 1; i < this._innerTree.length && this.getLevel(node) < this._innerTree[i].level; i++) { - result.push(this._innerTree[i]); - } - return result; - } - - selectNode(node: ITreeNode): void { - this._setNodeValue(node, 'selected', true); - } - - checkNode(node: ITreeNode): void { - this._setNodeValue(node, 'checked', true); - } - - uncheckNode(node: ITreeNode): void { - this._setNodeValue(node, 'checked', false); - } - - expandNode(node: ITreeNode): void { - this._setNodeValue(node, 'expanded', true); - } - - collapseNode(node: ITreeNode): void { - this._setNodeValue(node, 'expanded', false); - } - - toggleNode(node: ITreeNode): void { - if (node.expanded) { - this._setNodeValue(node, 'expanded', false); - } else { - this._setNodeValue(node, 'expanded', true); - } - } - - disableSelectNode(node: ITreeNode): void { - this._setNodeValue(node, 'disableSelect', true); - } - - disableCheckNode(node: ITreeNode): void { - this._setNodeValue(node, 'disableCheck', true); - } - - disableToggleNode(node: ITreeNode): void { - this._setNodeValue(node, 'disableToggle', true); - } - - insertBefore(parentNode: ITreeNode, node: ITreeNode, referenceNode: ITreeNode, cut: boolean = false): void { - // TODO - } - - removeNode(node: ITreeNode): void { - this._innerTree = this._innerTree.filter(item => { - return item.id !== node.id && !this.getChildren(node).map(nodeItem => nodeItem.id).includes(item.id); - }) - } - - editNode(node: ITreeNode, label: string): void { - this._setNodeValue(node, 'label', label); - } -} diff --git a/packages/devui-vue/devui/tree/src/core/use-check.ts b/packages/devui-vue/devui/tree/src/core/use-check.ts index b5999182d0..878a29096b 100644 --- a/packages/devui-vue/devui/tree/src/core/use-check.ts +++ b/packages/devui-vue/devui/tree/src/core/use-check.ts @@ -2,8 +2,6 @@ import { Ref } from 'vue'; import { IInnerTreeNode, IUseCore } from './tree-factory-types'; export default function useCheck(data: Ref, core: IUseCore) { - console.log('useCheck:', data, data.value); - const { setNodeValue, getNode } = core; const checkNode = (node: IInnerTreeNode): void => { diff --git a/packages/devui-vue/devui/tree/src/core/use-core.ts b/packages/devui-vue/devui/tree/src/core/use-core.ts index 77b5d87f31..51f1930a6c 100644 --- a/packages/devui-vue/devui/tree/src/core/use-core.ts +++ b/packages/devui-vue/devui/tree/src/core/use-core.ts @@ -16,14 +16,13 @@ export default function useCore(data: Ref): IUseCore { for (let i = startIndex + 1; i < data.value.length && getLevel(node) < data.value[i].level; i++) { result.push(data.value[i]); } - console.log('result:', result); return result; } const getExpendedTree = (): ComputedRef => { return computed(() => { - let excludeNodes = []; + let excludeNodes: IInnerTreeNode[] = []; let result = []; for (let i = 0, len = data?.value.length; i < len; i++) { diff --git a/packages/devui-vue/devui/tree/src/core/use-disable.ts b/packages/devui-vue/devui/tree/src/core/use-disable.ts index d524c48ccf..9840dccd2a 100644 --- a/packages/devui-vue/devui/tree/src/core/use-disable.ts +++ b/packages/devui-vue/devui/tree/src/core/use-disable.ts @@ -17,10 +17,25 @@ export default function useDisable(data: Ref, core: IUseCore) const disableToggleNode = (node: IInnerTreeNode): void => { setNodeValue(node, 'disableToggle', true); } + + const enableSelectNode = (node: IInnerTreeNode): void => { + setNodeValue(node, 'disableSelect', false); + } + + const enableCheckNode = (node: IInnerTreeNode): void => { + setNodeValue(node, 'disableCheck', false); + } + + const enableToggleNode = (node: IInnerTreeNode): void => { + setNodeValue(node, 'disableToggle', false); + } return { disableSelectNode, disableCheckNode, disableToggleNode, + enableSelectNode, + enableCheckNode, + enableToggleNode, } } \ No newline at end of file diff --git a/packages/devui-vue/devui/tree/src/core/use-operate.ts b/packages/devui-vue/devui/tree/src/core/use-operate.ts index a01a7d9b3f..fdc5d3fc43 100644 --- a/packages/devui-vue/devui/tree/src/core/use-operate.ts +++ b/packages/devui-vue/devui/tree/src/core/use-operate.ts @@ -16,7 +16,7 @@ export default function useOperate(data: Ref, core: IUseCore) }) } - const editNode = (node: ITreeNode, label: string): void => { + const editNode = (node: IInnerTreeNode, label: string): void => { setNodeValue(node, 'label', label); } diff --git a/packages/devui-vue/devui/tree/src/core/use-select.ts b/packages/devui-vue/devui/tree/src/core/use-select.ts index 2f046a4af7..6510c55d67 100644 --- a/packages/devui-vue/devui/tree/src/core/use-select.ts +++ b/packages/devui-vue/devui/tree/src/core/use-select.ts @@ -2,19 +2,20 @@ import { ref, Ref } from 'vue'; import { IInnerTreeNode, IUseCore } from './tree-factory-types'; export default function useSelect(data: Ref, core: IUseCore) { - console.log('useSelect:', data, data.value); - const { setNodeValue } = core; let prevActiveNode: IInnerTreeNode; const selectNode = (node: IInnerTreeNode): void => { if (node.disableSelect) { return; } + if (node.id === prevActiveNode?.id) { return; } + if (prevActiveNode) { const prevActiveNodeIndex = data.value.findIndex(item => item.id === prevActiveNode.id) setNodeValue(data.value[prevActiveNodeIndex], 'selected', false); } + setNodeValue(node, 'selected', true); prevActiveNode = node; } diff --git a/packages/devui-vue/devui/tree/src/core/use-toggle.ts b/packages/devui-vue/devui/tree/src/core/use-toggle.ts index cebf7aa1d0..f7390cc032 100644 --- a/packages/devui-vue/devui/tree/src/core/use-toggle.ts +++ b/packages/devui-vue/devui/tree/src/core/use-toggle.ts @@ -1,21 +1,23 @@ import { Ref } from 'vue'; -import { IInnerTreeNode, ITreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, IUseCore } from './tree-factory-types'; export default function useToggle(data: Ref, core: IUseCore) { - console.log('useToggle:', data, data.value); - const { getNode, setNodeValue } = core; const expandNode = (node: IInnerTreeNode): void => { + if (node.disableToggle) { return; } + setNodeValue(node, 'expanded', true); } const collapseNode = (node: IInnerTreeNode): void => { + if (node.disableToggle) { return; } + setNodeValue(node, 'expanded', false); } const toggleNode = (node: IInnerTreeNode): void => { - console.log('toggleNode node:', node); + if (node.disableToggle) { return; } if (getNode(node).expanded) { setNodeValue(node, 'expanded', false); diff --git a/packages/devui-vue/docs/components/tree/index.md b/packages/devui-vue/docs/components/tree/index.md index 773ac3e5b4..ffadb86ab5 100644 --- a/packages/devui-vue/docs/components/tree/index.md +++ b/packages/devui-vue/docs/components/tree/index.md @@ -1031,7 +1031,7 @@ export default defineComponent({ ``` ::: -### NewTree +### useTree :::demo @@ -1053,6 +1053,9 @@ export default defineComponent({ { label: 'Parent node 1-1', id: 'node-1-1', + disableCheck: true, + disableSelect: true, + disableToggle: true, children: [ { label: 'Leaf node 1-1-1', From 2e151631d9a050626133d8199f5358ab26cc08f8 Mon Sep 17 00:00:00 2001 From: Kagol Date: Sat, 2 Apr 2022 17:48:26 +0800 Subject: [PATCH 6/6] refactor(tree): tree-factory-types.ts -> use-tree-types.ts --- .../devui-vue/devui/tree/src/components/tree-node-toggle.tsx | 2 +- packages/devui-vue/devui/tree/src/components/tree-node.tsx | 2 +- packages/devui-vue/devui/tree/src/core/use-check.ts | 2 +- packages/devui-vue/devui/tree/src/core/use-core.ts | 2 +- packages/devui-vue/devui/tree/src/core/use-disable.ts | 4 +--- packages/devui-vue/devui/tree/src/core/use-operate.ts | 2 +- packages/devui-vue/devui/tree/src/core/use-select.ts | 2 +- packages/devui-vue/devui/tree/src/core/use-toggle.ts | 2 +- .../src/core/{tree-factory-types.ts => use-tree-types.ts} | 0 packages/devui-vue/devui/tree/src/core/use-tree.ts | 2 +- packages/devui-vue/devui/tree/src/core/utils.ts | 2 +- packages/devui-vue/devui/tree/src/new-tree.tsx | 2 +- 12 files changed, 11 insertions(+), 13 deletions(-) rename packages/devui-vue/devui/tree/src/core/{tree-factory-types.ts => use-tree-types.ts} (100%) diff --git a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx index 632b5790b8..10e6619b41 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node-toggle.tsx @@ -1,6 +1,6 @@ import { defineComponent, inject, PropType, toRefs } from 'vue'; import { USE_TREE_TOKEN } from '../const'; -import { ITreeNode } from '../core/tree-factory-types'; +import { ITreeNode } from '../core/use-tree-types'; import { IconClose } from './icon-close'; import { IconOpen } from './icon-open'; diff --git a/packages/devui-vue/devui/tree/src/components/tree-node.tsx b/packages/devui-vue/devui/tree/src/components/tree-node.tsx index a63decb0e7..fa1df6dde5 100644 --- a/packages/devui-vue/devui/tree/src/components/tree-node.tsx +++ b/packages/devui-vue/devui/tree/src/components/tree-node.tsx @@ -1,6 +1,6 @@ import { defineComponent, inject, PropType, toRefs } from 'vue'; import { USE_TREE_TOKEN } from '../const'; -import { IInnerTreeNode } from '../core/tree-factory-types'; +import { IInnerTreeNode } from '../core/use-tree-types'; import DTreeNodeToggle from './tree-node-toggle'; import { Checkbox } from '../../../checkbox'; diff --git a/packages/devui-vue/devui/tree/src/core/use-check.ts b/packages/devui-vue/devui/tree/src/core/use-check.ts index 878a29096b..30f986595a 100644 --- a/packages/devui-vue/devui/tree/src/core/use-check.ts +++ b/packages/devui-vue/devui/tree/src/core/use-check.ts @@ -1,5 +1,5 @@ import { Ref } from 'vue'; -import { IInnerTreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, IUseCore } from './use-tree-types'; export default function useCheck(data: Ref, core: IUseCore) { const { setNodeValue, getNode } = core; diff --git a/packages/devui-vue/devui/tree/src/core/use-core.ts b/packages/devui-vue/devui/tree/src/core/use-core.ts index 51f1930a6c..fa3ef76074 100644 --- a/packages/devui-vue/devui/tree/src/core/use-core.ts +++ b/packages/devui-vue/devui/tree/src/core/use-core.ts @@ -1,5 +1,5 @@ import { computed, ComputedRef, Ref } from 'vue'; -import { IInnerTreeNode, ITreeNode, IUseCore, valueof } from './tree-factory-types'; +import { IInnerTreeNode, ITreeNode, IUseCore, valueof } from './use-tree-types'; import { generateInnerTree } from './utils'; export default function useCore(data: Ref): IUseCore { diff --git a/packages/devui-vue/devui/tree/src/core/use-disable.ts b/packages/devui-vue/devui/tree/src/core/use-disable.ts index 9840dccd2a..259b4a218c 100644 --- a/packages/devui-vue/devui/tree/src/core/use-disable.ts +++ b/packages/devui-vue/devui/tree/src/core/use-disable.ts @@ -1,9 +1,7 @@ import { Ref } from 'vue'; -import { IInnerTreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, IUseCore } from './use-tree-types'; export default function useDisable(data: Ref, core: IUseCore) { - console.log('useDisable:', data, data.value); - const { setNodeValue } = core; const disableSelectNode = (node: IInnerTreeNode): void => { diff --git a/packages/devui-vue/devui/tree/src/core/use-operate.ts b/packages/devui-vue/devui/tree/src/core/use-operate.ts index fdc5d3fc43..c1a6956e55 100644 --- a/packages/devui-vue/devui/tree/src/core/use-operate.ts +++ b/packages/devui-vue/devui/tree/src/core/use-operate.ts @@ -1,5 +1,5 @@ import { Ref } from 'vue'; -import { IInnerTreeNode, ITreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, ITreeNode, IUseCore } from './use-tree-types'; export default function useOperate(data: Ref, core: IUseCore) { console.log('useOperate:', data, data.value); diff --git a/packages/devui-vue/devui/tree/src/core/use-select.ts b/packages/devui-vue/devui/tree/src/core/use-select.ts index 6510c55d67..14378f0008 100644 --- a/packages/devui-vue/devui/tree/src/core/use-select.ts +++ b/packages/devui-vue/devui/tree/src/core/use-select.ts @@ -1,5 +1,5 @@ import { ref, Ref } from 'vue'; -import { IInnerTreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, IUseCore } from './use-tree-types'; export default function useSelect(data: Ref, core: IUseCore) { const { setNodeValue } = core; diff --git a/packages/devui-vue/devui/tree/src/core/use-toggle.ts b/packages/devui-vue/devui/tree/src/core/use-toggle.ts index f7390cc032..cbdfdad712 100644 --- a/packages/devui-vue/devui/tree/src/core/use-toggle.ts +++ b/packages/devui-vue/devui/tree/src/core/use-toggle.ts @@ -1,5 +1,5 @@ import { Ref } from 'vue'; -import { IInnerTreeNode, IUseCore } from './tree-factory-types'; +import { IInnerTreeNode, IUseCore } from './use-tree-types'; export default function useToggle(data: Ref, core: IUseCore) { const { getNode, setNodeValue } = core; diff --git a/packages/devui-vue/devui/tree/src/core/tree-factory-types.ts b/packages/devui-vue/devui/tree/src/core/use-tree-types.ts similarity index 100% rename from packages/devui-vue/devui/tree/src/core/tree-factory-types.ts rename to packages/devui-vue/devui/tree/src/core/use-tree-types.ts diff --git a/packages/devui-vue/devui/tree/src/core/use-tree.ts b/packages/devui-vue/devui/tree/src/core/use-tree.ts index b737c77723..393c97b951 100644 --- a/packages/devui-vue/devui/tree/src/core/use-tree.ts +++ b/packages/devui-vue/devui/tree/src/core/use-tree.ts @@ -1,5 +1,5 @@ import { ref } from 'vue'; -import { IInnerTreeNode, ITreeNode, IUseCore, IUseTree } from './tree-factory-types'; +import { IInnerTreeNode, ITreeNode, IUseCore, IUseTree } from './use-tree-types'; import useToggle from './use-toggle'; import useCore from './use-core'; import { generateInnerTree } from './utils'; diff --git a/packages/devui-vue/devui/tree/src/core/utils.ts b/packages/devui-vue/devui/tree/src/core/utils.ts index d14d57ba3c..a6e2c5478a 100644 --- a/packages/devui-vue/devui/tree/src/core/utils.ts +++ b/packages/devui-vue/devui/tree/src/core/utils.ts @@ -1,5 +1,5 @@ import { randomId } from '../../../anchor/src/util'; -import { IInnerTreeNode, ITreeNode } from './tree-factory-types'; +import { IInnerTreeNode, ITreeNode } from './use-tree-types'; export function flatToNested(flatTree: IInnerTreeNode[]): ITreeNode[] { let treeMap = {}; diff --git a/packages/devui-vue/devui/tree/src/new-tree.tsx b/packages/devui-vue/devui/tree/src/new-tree.tsx index 8d283aa211..aed82a358b 100644 --- a/packages/devui-vue/devui/tree/src/new-tree.tsx +++ b/packages/devui-vue/devui/tree/src/new-tree.tsx @@ -1,5 +1,5 @@ import { defineComponent, PropType, provide, toRefs, watch } from 'vue'; -import type { ITreeNode } from './core/tree-factory-types'; +import type { ITreeNode } from './core/use-tree-types'; import DTreeNode from './components/tree-node'; import useTree from './core/use-tree'; import useCheck from './core/use-check';