Commit 72b42d7b3539919a9baa4f1a7316842f85991c1e

Authored by Vben
1 parent d67bd496

feat(tree): add renderIcon props close #309

CHANGELOG.zh_CN.md
... ... @@ -11,6 +11,7 @@
11 11 - 新增修改密码界面
12 12 - 新增部门管理示例界面
13 13 - 新增 WebSocket 示例和服务脚本
  14 +- BasicTree 组件新增 `renderIcon` 属性用于控制层级图标显示
14 15  
15 16 ### ⚡ Performance Improvements
16 17  
... ...
src/components/Tree/index.ts
1   -import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
2   -
3   -export const BasicTree = createAsyncComponent(() => import('./src/BasicTree'));
  1 +import BasicTree from './src/index.vue';
4 2  
  3 +export { BasicTree };
5 4 export type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
6 5 export * from './src/types';
... ...
src/components/Tree/src/TreeIcon.ts 0 → 100644
  1 +import type { VNode, FunctionalComponent } from 'vue';
  2 +
  3 +import { h } from 'vue';
  4 +import { isString } from '/@/utils/is';
  5 +import { Icon } from '/@/components/Icon';
  6 +
  7 +export interface ComponentProps {
  8 + icon: VNode | string;
  9 +}
  10 +
  11 +export const TreeIcon: FunctionalComponent = ({ icon }: ComponentProps) => {
  12 + if (!icon) return null;
  13 + if (isString(icon)) {
  14 + return h(Icon, { icon, class: 'mr-1' });
  15 + }
  16 + return Icon;
  17 +};
... ...
src/components/Tree/src/index.less deleted 100644 → 0
1   -.basic-tree {
2   - position: relative;
3   -
4   - &-title {
5   - position: relative;
6   - display: inline-block;
7   - width: 100%;
8   - padding-right: 10px;
9   -
10   - &:hover {
11   - .basic-tree__action {
12   - visibility: visible;
13   - }
14   - }
15   - }
16   -
17   - &__content {
18   - display: inline-block;
19   - overflow: hidden;
20   - }
21   -
22   - &__actions {
23   - position: absolute;
24   - top: 0;
25   - right: 0;
26   - display: flex;
27   - }
28   -
29   - &__action {
30   - margin-left: 4px;
31   - // float: right;
32   - // display: none;
33   - visibility: hidden;
34   - }
35   -}
src/components/Tree/src/BasicTree.tsx renamed to src/components/Tree/src/index.vue
1   -import './index.less';
2   -
3   -import type { ReplaceFields, TreeItem, Keys, CheckKeys, TreeActionType } from './types';
4   -
5   -import { defineComponent, reactive, computed, unref, ref, watchEffect, CSSProperties } from 'vue';
6   -import { Tree } from 'ant-design-vue';
7   -import { DownOutlined } from '@ant-design/icons-vue';
8   -
9   -import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
10   -
11   -import { isFunction } from '/@/utils/is';
12   -import { omit } from 'lodash-es';
13   -import { extendSlots } from '/@/utils/helper/tsxHelper';
14   -
15   -import { basicProps } from './props';
16   -import { useTree } from './useTree';
17   -import { useExpose } from '/@/hooks/core/useExpose';
18   -import { onMounted } from 'vue';
19   -
20   -interface State {
21   - expandedKeys: Keys;
22   - selectedKeys: Keys;
23   - checkedKeys: CheckKeys;
24   -}
25   -const prefixCls = 'basic-tree';
26   -export default defineComponent({
27   - name: 'BasicTree',
28   - props: basicProps,
29   - emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
30   - setup(props, { attrs, slots, emit }) {
31   - const state = reactive<State>({
32   - expandedKeys: props.expandedKeys || [],
33   - selectedKeys: props.selectedKeys || [],
34   - checkedKeys: props.checkedKeys || [],
35   - });
36   -
37   - const treeDataRef = ref<TreeItem[]>([]);
38   -
39   - const [createContextMenu] = useContextMenu();
40   -
41   - const getReplaceFields = computed(
42   - (): Required<ReplaceFields> => {
43   - const { replaceFields } = props;
44   - return {
45   - children: 'children',
46   - title: 'title',
47   - key: 'key',
48   - ...replaceFields,
  1 +<script lang="tsx">
  2 + import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
  3 +
  4 + import { defineComponent, reactive, computed, unref, ref, watchEffect, onMounted } from 'vue';
  5 + import { Tree } from 'ant-design-vue';
  6 + import { TreeIcon } from './TreeIcon';
  7 + // import { DownOutlined } from '@ant-design/icons-vue';
  8 +
  9 + import { omit, get } from 'lodash-es';
  10 + import { isFunction } from '/@/utils/is';
  11 + import { extendSlots } from '/@/utils/helper/tsxHelper';
  12 +
  13 + import { useTree } from './useTree';
  14 + import { useContextMenu, ContextMenuItem } from '/@/hooks/web/useContextMenu';
  15 + import { useExpose } from '/@/hooks/core/useExpose';
  16 + import { useDesign } from '/@/hooks/web/useDesign';
  17 +
  18 + import { basicProps } from './props';
  19 +
  20 + interface State {
  21 + expandedKeys: Keys;
  22 + selectedKeys: Keys;
  23 + checkedKeys: CheckKeys;
  24 + }
  25 + export default defineComponent({
  26 + name: 'BasicTree',
  27 + props: basicProps,
  28 + emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'get'],
  29 + setup(props, { attrs, slots, emit }) {
  30 + const state = reactive<State>({
  31 + expandedKeys: props.expandedKeys || [],
  32 + selectedKeys: props.selectedKeys || [],
  33 + checkedKeys: props.checkedKeys || [],
  34 + });
  35 +
  36 + const treeDataRef = ref<TreeItem[]>([]);
  37 +
  38 + const [createContextMenu] = useContextMenu();
  39 + const { prefixCls } = useDesign('basic-tree');
  40 +
  41 + const getReplaceFields = computed(
  42 + (): Required<ReplaceFields> => {
  43 + const { replaceFields } = props;
  44 + return {
  45 + children: 'children',
  46 + title: 'title',
  47 + key: 'key',
  48 + ...replaceFields,
  49 + };
  50 + }
  51 + );
  52 +
  53 + // const getContentStyle = computed(
  54 + // (): CSSProperties => {
  55 + // const { actionList } = props;
  56 + // const width = actionList.length * 18;
  57 + // return {
  58 + // width: `calc(100% - ${width}px)`,
  59 + // };
  60 + // }
  61 + // );
  62 +
  63 + const getBindValues = computed(() => {
  64 + let propsData = {
  65 + blockNode: true,
  66 + ...attrs,
  67 + ...props,
  68 + expandedKeys: state.expandedKeys,
  69 + selectedKeys: state.selectedKeys,
  70 + checkedKeys: state.checkedKeys,
  71 + replaceFields: unref(getReplaceFields),
  72 + 'onUpdate:expandedKeys': (v: Keys) => {
  73 + state.expandedKeys = v;
  74 + emit('update:expandedKeys', v);
  75 + },
  76 + 'onUpdate:selectedKeys': (v: Keys) => {
  77 + state.selectedKeys = v;
  78 + emit('update:selectedKeys', v);
  79 + },
  80 + onCheck: (v: CheckKeys, e) => {
  81 + state.checkedKeys = v;
  82 + console.log(e);
  83 + emit('update:value', v);
  84 + },
  85 + onRightClick: handleRightClick,
49 86 };
  87 + propsData = omit(propsData, 'treeData');
  88 + return propsData;
  89 + });
  90 +
  91 + const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
  92 +
  93 + const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
  94 + treeDataRef,
  95 + getReplaceFields
  96 + );
  97 +
  98 + function getIcon(params: Recordable, icon?: string) {
  99 + if (!icon) {
  100 + if (props.renderIcon && isFunction(props.renderIcon)) {
  101 + return props.renderIcon(params);
  102 + }
  103 + }
  104 + return icon;
50 105 }
51   - );
52 106  
53   - const getContentStyle = computed(
54   - (): CSSProperties => {
  107 + function renderAction(node: TreeItem) {
55 108 const { actionList } = props;
56   - const width = actionList.length * 18;
57   - return {
58   - width: `calc(100% - ${width}px)`,
59   - };
  109 + if (!actionList || actionList.length === 0) return;
  110 + return actionList.map((item, index) => {
  111 + return (
  112 + <span key={index} class={`${prefixCls}__action`}>
  113 + {item.render(node)}
  114 + </span>
  115 + );
  116 + });
60 117 }
61   - );
62   -
63   - const getBindValues = computed(() => {
64   - let propsData = {
65   - blockNode: true,
66   - ...attrs,
67   - ...props,
68   - expandedKeys: state.expandedKeys,
69   - selectedKeys: state.selectedKeys,
70   - checkedKeys: state.checkedKeys,
71   - replaceFields: unref(getReplaceFields),
72   - 'onUpdate:expandedKeys': (v: Keys) => {
73   - state.expandedKeys = v;
74   - emit('update:expandedKeys', v);
75   - },
76   - 'onUpdate:selectedKeys': (v: Keys) => {
77   - state.selectedKeys = v;
78   - emit('update:selectedKeys', v);
79   - },
80   - onCheck: (v: CheckKeys) => {
81   - state.checkedKeys = v;
82   - emit('update:value', v);
83   - },
84   - onRightClick: handleRightClick,
85   - };
86   - propsData = omit(propsData, 'treeData');
87   - return propsData;
88   - });
89 118  
90   - const getTreeData = computed((): TreeItem[] => unref(treeDataRef));
  119 + function renderTreeNode({ data, level }: { data: TreeItem[] | undefined; level: number }) {
  120 + if (!data) {
  121 + return null;
  122 + }
  123 + return data.map((item) => {
  124 + const { title: titleField, key: keyField, children: childrenField } = unref(
  125 + getReplaceFields
  126 + );
91 127  
92   - const { deleteNodeByKey, insertNodeByKey, filterByLevel, updateNodeByKey } = useTree(
93   - treeDataRef,
94   - getReplaceFields
95   - );
  128 + const propsData = omit(item, 'title');
  129 + const icon = getIcon({ ...item, level }, item.icon);
  130 + return (
  131 + <Tree.TreeNode {...propsData} key={get(item, keyField)}>
  132 + {{
  133 + title: () => (
  134 + <span class={`${prefixCls}-title`}>
  135 + {icon && <TreeIcon icon={icon} />}
  136 + <span
  137 + class={`${prefixCls}__content`}
  138 + // style={unref(getContentStyle)}
  139 + >
  140 + {get(item, titleField)}
  141 + </span>
  142 + <span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
  143 + </span>
  144 + ),
  145 + default: () =>
  146 + renderTreeNode({ data: get(item, childrenField) || [], level: level + 1 }),
  147 + }}
  148 + </Tree.TreeNode>
  149 + );
  150 + });
  151 + }
96 152  
97   - // 渲染操作按钮
98   - function renderAction(node: TreeItem) {
99   - const { actionList } = props;
  153 + async function handleRightClick({ event, node }: any) {
  154 + const { rightMenuList: menuList = [], beforeRightClick } = props;
  155 + let rightMenuList: ContextMenuItem[] = [];
100 156  
101   - if (!actionList || actionList.length === 0) return;
  157 + if (beforeRightClick && isFunction(beforeRightClick)) {
  158 + rightMenuList = await beforeRightClick(node);
  159 + } else {
  160 + rightMenuList = menuList;
  161 + }
  162 + if (!rightMenuList.length) return;
  163 + createContextMenu({
  164 + event,
  165 + items: rightMenuList,
  166 + });
  167 + }
102 168  
103   - return actionList.map((item, index) => {
104   - return (
105   - <span key={index} class={`${prefixCls}__action`}>
106   - {item.render(node)}
107   - </span>
108   - );
109   - });
110   - }
111   - // 渲染树节点
112   - function renderTreeNode({ data }: { data: TreeItem[] | undefined }) {
113   - if (!data) {
114   - return null;
  169 + function setExpandedKeys(keys: string[]) {
  170 + state.expandedKeys = keys;
115 171 }
116   - return data.map((item) => {
117   - const { title: titleField, key: keyField, children: childrenField } = unref(
118   - getReplaceFields
119   - );
120   - const propsData = omit(item, 'title');
121   - const anyItem = item as any;
  172 +
  173 + function getExpandedKeys() {
  174 + return state.expandedKeys;
  175 + }
  176 + function setSelectedKeys(keys: string[]) {
  177 + state.selectedKeys = keys;
  178 + }
  179 +
  180 + function getSelectedKeys() {
  181 + return state.selectedKeys;
  182 + }
  183 +
  184 + function setCheckedKeys(keys: CheckKeys) {
  185 + state.checkedKeys = keys;
  186 + }
  187 +
  188 + function getCheckedKeys() {
  189 + return state.checkedKeys;
  190 + }
  191 +
  192 + watchEffect(() => {
  193 + treeDataRef.value = props.treeData as TreeItem[];
  194 + state.expandedKeys = props.expandedKeys;
  195 + state.selectedKeys = props.selectedKeys;
  196 + state.checkedKeys = props.checkedKeys;
  197 + });
  198 +
  199 + const instance: TreeActionType = {
  200 + setExpandedKeys,
  201 + getExpandedKeys,
  202 + setSelectedKeys,
  203 + getSelectedKeys,
  204 + setCheckedKeys,
  205 + getCheckedKeys,
  206 + insertNodeByKey,
  207 + deleteNodeByKey,
  208 + updateNodeByKey,
  209 + filterByLevel: (level: number) => {
  210 + state.expandedKeys = filterByLevel(level);
  211 + },
  212 + };
  213 +
  214 + useExpose<TreeActionType>(instance);
  215 +
  216 + onMounted(() => {
  217 + emit('get', instance);
  218 + });
  219 +
  220 + return () => {
122 221 return (
123   - <Tree.TreeNode {...propsData} key={anyItem?.[keyField]}>
  222 + <Tree {...unref(getBindValues)} showIcon={false} class={[prefixCls]}>
124 223 {{
125   - title: () => (
126   - <span class={`${prefixCls}-title`}>
127   - <span class={`${prefixCls}__content`} style={unref(getContentStyle)}>
128   - {titleField && anyItem[titleField]}
129   - </span>
130   - <span class={`${prefixCls}__actions`}> {renderAction(item)}</span>
131   - </span>
132   - ),
133   - default: () => renderTreeNode({ data: childrenField ? anyItem[childrenField] : [] }),
  224 + // switcherIcon: () => <DownOutlined />,
  225 + default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
  226 + ...extendSlots(slots),
134 227 }}
135   - </Tree.TreeNode>
  228 + </Tree>
136 229 );
137   - });
138   - }
  230 + };
  231 + },
  232 + });
  233 +</script>
  234 +<style lang="less">
  235 + @prefix-cls: ~'@{namespace}-basic-tree';
  236 +
  237 + .@{prefix-cls} {
  238 + position: relative;
139 239  
140   - // 处理右键事件
141   - async function handleRightClick({ event, node }: any) {
142   - const { rightMenuList: menuList = [], beforeRightClick } = props;
143   - let rightMenuList: ContextMenuItem[] = [];
144   - if (beforeRightClick && isFunction(beforeRightClick)) {
145   - rightMenuList = await beforeRightClick(node);
146   - } else {
147   - rightMenuList = menuList;
  240 + .ant-tree-node-content-wrapper {
  241 + position: relative;
  242 +
  243 + .ant-tree-title {
  244 + position: absolute;
  245 + left: 0;
  246 + width: 100%;
148 247 }
149   - if (!rightMenuList.length) return;
150   - createContextMenu({
151   - event,
152   - items: rightMenuList,
153   - });
154 248 }
155 249  
156   - function setExpandedKeys(keys: string[]) {
157   - state.expandedKeys = keys;
158   - }
  250 + &-title {
  251 + position: relative;
  252 + display: flex;
  253 + align-items: center;
  254 + width: 100%;
  255 + padding-right: 10px;
159 256  
160   - function getExpandedKeys() {
161   - return state.expandedKeys;
162   - }
163   - function setSelectedKeys(keys: string[]) {
164   - state.selectedKeys = keys;
  257 + &:hover {
  258 + .@{prefix-cls}__action {
  259 + visibility: visible;
  260 + }
  261 + }
165 262 }
166 263  
167   - function getSelectedKeys() {
168   - return state.selectedKeys;
  264 + &__content {
  265 + display: inline-block;
  266 + overflow: hidden;
169 267 }
170 268  
171   - function setCheckedKeys(keys: CheckKeys) {
172   - state.checkedKeys = keys;
  269 + &__actions {
  270 + position: absolute;
  271 + top: 2px;
  272 + right: 2px;
  273 + display: flex;
173 274 }
174 275  
175   - function getCheckedKeys() {
176   - return state.checkedKeys;
  276 + &__action {
  277 + margin-left: 4px;
  278 + visibility: hidden;
177 279 }
178   -
179   - watchEffect(() => {
180   - treeDataRef.value = props.treeData as TreeItem[];
181   - state.expandedKeys = props.expandedKeys;
182   - state.selectedKeys = props.selectedKeys;
183   - state.checkedKeys = props.checkedKeys;
184   - });
185   -
186   - const instance: TreeActionType = {
187   - setExpandedKeys,
188   - getExpandedKeys,
189   - setSelectedKeys,
190   - getSelectedKeys,
191   - setCheckedKeys,
192   - getCheckedKeys,
193   - insertNodeByKey,
194   - deleteNodeByKey,
195   - updateNodeByKey,
196   - filterByLevel: (level: number) => {
197   - state.expandedKeys = filterByLevel(level);
198   - },
199   - };
200   -
201   - useExpose<TreeActionType>(instance);
202   -
203   - onMounted(() => {
204   - emit('get', instance);
205   - });
206   -
207   - return () => {
208   - return (
209   - <Tree {...(unref(getBindValues) as any)} class={prefixCls}>
210   - {{
211   - switcherIcon: () => <DownOutlined />,
212   - default: () => renderTreeNode({ data: unref(getTreeData) }),
213   - ...extendSlots(slots),
214   - }}
215   - </Tree>
216   - );
217   - };
218   - },
219   -});
  280 + }
  281 +</style>
... ...
src/components/Tree/src/props.ts
1   -import { PropType } from 'vue';
2   -import type { ReplaceFields, TreeItem, ActionItem, Keys, CheckKeys } from './types';
  1 +import type { PropType } from 'vue';
  2 +import type { ReplaceFields, ActionItem, Keys, CheckKeys } from './types';
3 3 import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
  4 +import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
4 5  
5 6 export const basicProps = {
  7 + renderIcon: {
  8 + type: Function as PropType<(params: Recordable) => string>,
  9 + },
6 10 replaceFields: {
7 11 type: Object as PropType<ReplaceFields>,
8 12 },
9 13  
10 14 treeData: {
11   - type: Array as PropType<TreeItem[]>,
  15 + type: Array as PropType<TreeDataItem[]>,
12 16 },
13 17  
14 18 actionList: {
... ... @@ -50,7 +54,7 @@ export const treeNodeProps = {
50 54 type: Object as PropType<ReplaceFields>,
51 55 },
52 56 treeData: {
53   - type: Array as PropType<TreeItem[]>,
  57 + type: Array as PropType<TreeDataItem[]>,
54 58 default: () => [],
55 59 },
56 60 };
... ...
src/components/Tree/src/types.ts
  1 +import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
1 2 export interface ActionItem {
2 3 render: (record: any) => any;
3 4 }
4 5  
5   -export interface TreeItem {
6   - /**
7   - * Class
8   - * @description className
9   - * @type string
10   - */
11   - class?: string;
12   -
13   - /**
14   - * Style
15   - * @description style of tree node
16   - * @type string | object
17   - */
18   - style?: string | object;
19   -
20   - /**
21   - * Disable Checkbox
22   - * @description Disables the checkbox of the treeNode
23   - * @default false
24   - * @type boolean
25   - */
26   - disableCheckbox?: boolean;
27   -
28   - /**
29   - * Disabled
30   - * @description Disabled or not
31   - * @default false
32   - * @type boolean
33   - */
34   - disabled?: boolean;
35   -
36   - /**
37   - * Icon
38   - * @description customize icon. When you pass component, whose render will receive full TreeNode props as component props
39   - * @type any (slot | slot-scope)
40   - */
  6 +export interface TreeItem extends TreeDataItem {
41 7 icon?: any;
42   -
43   - /**
44   - * Is Leaf?
45   - * @description Leaf node or not
46   - * @default false
47   - * @type boolean
48   - */
49   - isLeaf?: boolean;
50   -
51   - /**
52   - * Key
53   - * @description Required property, should be unique in the tree
54   - * (In tree: Used with (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys)
55   - * @default internal calculated position of treeNode or undefined
56   - * @type string | number
57   - */
58   - key: string | number;
59   -
60   - /**
61   - * Selectable
62   - * @description Set whether the treeNode can be selected
63   - * @default true
64   - * @type boolean
65   - */
66   - selectable?: boolean;
67   -
68   - /**
69   - * Title
70   - * @description Content showed on the treeNodes
71   - * @default '---'
72   - * @type any (string | slot)
73   - */
74   - title: any;
75   -
76   - /**
77   - * Value
78   - * @description Will be treated as treeNodeFilterProp by default, should be unique in the tree
79   - * @default undefined
80   - * @type string
81   - */
82   - value?: string;
83   - children?: TreeItem[];
84   - slots?: any;
85   - scopedSlots?: any;
86 8 }
87 9  
88 10 export interface ReplaceFields {
... ... @@ -107,12 +29,12 @@ export interface TreeActionType {
107 29 filterByLevel: (level: number) => void;
108 30 insertNodeByKey: (opt: InsertNodeParams) => void;
109 31 deleteNodeByKey: (key: string) => void;
110   - updateNodeByKey: (key: string, node: Omit<TreeItem, 'key'>) => void;
  32 + updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void;
111 33 }
112 34  
113 35 export interface InsertNodeParams {
114 36 parentKey: string | null;
115   - node: TreeItem;
116   - list?: TreeItem[];
  37 + node: TreeDataItem;
  38 + list?: TreeDataItem[];
117 39 push?: 'push' | 'unshift';
118 40 }
... ...
src/components/Tree/src/useTree.ts
1   -import type { InsertNodeParams, ReplaceFields, TreeItem } from './types';
  1 +import type { InsertNodeParams, ReplaceFields } from './types';
2 2 import type { Ref, ComputedRef } from 'vue';
  3 +import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
3 4  
4 5 import { cloneDeep } from 'lodash-es';
5 6 import { unref } from 'vue';
6 7 import { forEach } from '/@/utils/helper/treeHelper';
7 8  
8 9 export function useTree(
9   - treeDataRef: Ref<TreeItem[]>,
  10 + treeDataRef: Ref<TreeDataItem[]>,
10 11 getReplaceFields: ComputedRef<ReplaceFields>
11 12 ) {
12   - // 更新节点
13   - function updateNodeByKey(key: string, node: TreeItem, list?: TreeItem[]) {
  13 + // Update node
  14 + function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) {
14 15 if (!key) return;
15 16 const treeData = list || unref(treeDataRef);
16 17 const { key: keyField, children: childrenField } = unref(getReplaceFields);
... ... @@ -30,8 +31,8 @@ export function useTree(
30 31 }
31 32 }
32 33  
33   - // 展开指定级别
34   - function filterByLevel(level = 1, list?: TreeItem[], currentLevel = 1) {
  34 + // Expand the specified level
  35 + function filterByLevel(level = 1, list?: TreeDataItem[], currentLevel = 1) {
35 36 if (!level) {
36 37 return [];
37 38 }
... ... @@ -74,8 +75,8 @@ export function useTree(
74 75 treeDataRef.value = treeData;
75 76 }
76 77  
77   - // 删除节点
78   - function deleteNodeByKey(key: string, list?: TreeItem[]) {
  78 + // Delete node
  79 + function deleteNodeByKey(key: string, list?: TreeDataItem[]) {
79 80 if (!key) return;
80 81 const treeData = list || unref(treeDataRef);
81 82 const { key: keyField, children: childrenField } = unref(getReplaceFields);
... ...
src/views/demo/tree/ActionTree.vue
... ... @@ -35,6 +35,7 @@
35 35 setup() {
36 36 const treeRef = ref<Nullable<TreeActionType>>(null);
37 37 const { createMessage } = useMessage();
  38 +
38 39 function getTree() {
39 40 const tree = unref(treeRef);
40 41 if (!tree) {
... ...
src/views/demo/tree/EditTree.vue
1 1 <template>
2 2 <PageWrapper title="Tree函数操作示例">
3 3 <div class="flex">
4   - <CollapseContainer title="右侧操作按钮" class="mr-4" :style="{ width: '33%' }">
5   - <BasicTree :treeData="treeData" :actionList="actionList" />
  4 + <CollapseContainer title="右侧操作按钮/自定义图标" class="mr-4" :style="{ width: '33%' }">
  5 + <BasicTree :treeData="treeData" :actionList="actionList" :renderIcon="createIcon" />
6 6 </CollapseContainer>
7 7  
8 8 <CollapseContainer title="右键菜单" class="mr-4" :style="{ width: '33%' }">
... ... @@ -61,7 +61,19 @@
61 61 },
62 62 },
63 63 ];
64   - return { treeData, actionList, getRightMenuList };
  64 +
  65 + function createIcon({ level }) {
  66 + if (level === 1) {
  67 + return 'ion:git-compare-outline';
  68 + }
  69 + if (level === 2) {
  70 + return 'ion:home';
  71 + }
  72 + if (level === 3) {
  73 + return 'ion:airplane';
  74 + }
  75 + }
  76 + return { treeData, actionList, getRightMenuList, createIcon };
65 77 },
66 78 });
67 79 </script>
... ...
src/views/demo/tree/data.ts
... ... @@ -2,9 +2,8 @@ import { TreeItem } from &#39;/@/components/Tree/index&#39;;
2 2  
3 3 export const treeData: TreeItem[] = [
4 4 {
5   - title: 'parent 1parent ',
  5 + title: 'parent ',
6 6 key: '0-0',
7   - icon: 'home|svg',
8 7 children: [
9 8 { title: 'leaf', key: '0-0-0' },
10 9 {
... ... @@ -20,7 +19,6 @@ export const treeData: TreeItem[] = [
20 19 {
21 20 title: 'parent 2',
22 21 key: '1-1',
23   - icon: 'home|svg',
24 22 children: [
25 23 { title: 'leaf', key: '1-1-0' },
26 24 { title: 'leaf', key: '1-1-1' },
... ... @@ -29,7 +27,6 @@ export const treeData: TreeItem[] = [
29 27 {
30 28 title: 'parent 3',
31 29 key: '2-2',
32   - icon: 'home|svg',
33 30 children: [
34 31 { title: 'leaf', key: '2-2-0' },
35 32 { title: 'leaf', key: '2-2-1' },
... ...