Skip to content

Commit 3dc6b07

Browse files
committed
feat: update tree and vc-tree
1 parent 2fb6667 commit 3dc6b07

18 files changed

+1599
-833
lines changed

components/tree/DirectoryTree.jsx

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import omit from 'omit.js'
2+
import debounce from 'lodash/debounce'
3+
import PropTypes from '../_util/vue-types'
4+
import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util'
5+
import Tree, { TreeProps } from './Tree'
6+
import { calcRangeKeys, getFullKeyList } from './util'
7+
import Icon from '../icon'
8+
import { initDefaultProps, getOptionProps } from '../_util/props-util'
9+
10+
// export type ExpandAction = false | 'click' | 'doubleClick';
11+
12+
// export interface DirectoryTreeProps extends TreeProps {
13+
// expandAction?: ExpandAction;
14+
// }
15+
16+
// export interface DirectoryTreeState {
17+
// expandedKeys?: string[];
18+
// selectedKeys?: string[];
19+
// }
20+
21+
function getIcon (h, props) {
22+
const { isLeaf, expanded } = props
23+
if (isLeaf) {
24+
return <Icon type='file' />
25+
}
26+
return <Icon type={expanded ? 'folder-open' : 'folder'} />
27+
}
28+
29+
export default {
30+
name: 'ADirectoryTree',
31+
model: {
32+
prop: 'checkedKeys',
33+
event: 'check',
34+
},
35+
props: initDefaultProps({ ...TreeProps(), expandAction: PropTypes.oneOf([false, 'click', 'doubleClick']) }, {
36+
prefixCls: 'ant-tree',
37+
showIcon: true,
38+
expandAction: 'click',
39+
}),
40+
41+
// state: DirectoryTreeState;
42+
// onDebounceExpand: (event, node: AntTreeNode) => void;
43+
44+
// // Shift click usage
45+
// lastSelectedKey?: string;
46+
// cachedSelectedKeys?: string[];
47+
48+
data () {
49+
const props = getOptionProps(this)
50+
const { defaultExpandAll, defaultExpandParent, expandedKeys, defaultExpandedKeys } = props
51+
const { keyEntities } = convertTreeToEntities(this.$slots.default)
52+
const state = {}
53+
// Selected keys
54+
state._selectedKeys = props.selectedKeys || props.defaultSelectedKeys || []
55+
56+
// Expanded keys
57+
if (defaultExpandAll) {
58+
state._expandedKeys = getFullKeyList(props.children)
59+
} else if (defaultExpandParent) {
60+
state._expandedKeys = conductExpandParent(expandedKeys || defaultExpandedKeys, keyEntities)
61+
} else {
62+
state._expandedKeys = defaultExpandedKeys
63+
}
64+
65+
this.onDebounceExpand = debounce(this.expandFolderNode, 200, {
66+
leading: true,
67+
})
68+
return {
69+
_selectedKeys: [],
70+
_expandedKeys: [],
71+
...state,
72+
}
73+
},
74+
watch: {
75+
expandedKeys (val) {
76+
this.setState({ _expandedKeys: val })
77+
},
78+
selectedKeys (val) {
79+
this.setState({ _selectedKeys: val })
80+
},
81+
},
82+
methods: {
83+
onExpand (expandedKeys, info) {
84+
this.setUncontrolledState({ _expandedKeys: expandedKeys })
85+
86+
this.$emit('expand', expandedKeys, info)
87+
88+
return undefined
89+
},
90+
91+
onClick (event, node) {
92+
const { expandAction } = this.$props
93+
94+
// Expand the tree
95+
if (expandAction === 'click') {
96+
this.onDebounceExpand(event, node)
97+
}
98+
this.$emit('click', event, node)
99+
},
100+
101+
onDoubleClick (event, node) {
102+
const { expandAction } = this.$props
103+
104+
// Expand the tree
105+
if (expandAction === 'doubleClick') {
106+
this.onDebounceExpand(event, node)
107+
}
108+
109+
this.$emit('doubleclick', event, node)
110+
},
111+
112+
onSelect (keys, event) {
113+
const { multiple } = this.$props
114+
const children = this.$slots.default || []
115+
const { _expandedKeys: expandedKeys = [], _selectedKeys: selectedKeys = [] } = this.$data
116+
const { node, nativeEvent } = event
117+
const { eventKey = '' } = node
118+
119+
const newState = {}
120+
121+
// Windows / Mac single pick
122+
const ctrlPick = nativeEvent.ctrlKey || nativeEvent.metaKey
123+
const shiftPick = nativeEvent.shiftKey
124+
125+
// Generate new selected keys
126+
let newSelectedKeys = selectedKeys.slice()
127+
if (multiple && ctrlPick) {
128+
// Control click
129+
newSelectedKeys = keys
130+
this.lastSelectedKey = eventKey
131+
this.cachedSelectedKeys = newSelectedKeys
132+
} else if (multiple && shiftPick) {
133+
// Shift click
134+
newSelectedKeys = Array.from(new Set([
135+
...this.cachedSelectedKeys || [],
136+
...calcRangeKeys(children, expandedKeys, eventKey, this.lastSelectedKey),
137+
]))
138+
} else {
139+
// Single click
140+
newSelectedKeys = [eventKey]
141+
this.lastSelectedKey = eventKey
142+
this.cachedSelectedKeys = newSelectedKeys
143+
}
144+
newState._selectedKeys = newSelectedKeys
145+
146+
this.$emit('select', newSelectedKeys, event)
147+
148+
this.setUncontrolledState(newState)
149+
},
150+
151+
expandFolderNode (event, node) {
152+
const { _expandedKeys: expandedKeys = [] } = this.$data
153+
const { eventKey = '', expanded, isLeaf } = node
154+
155+
if (isLeaf || event.shiftKey || event.metaKey || event.ctrlKey) {
156+
return
157+
}
158+
159+
const newExpandedKeys = expandedKeys.slice()
160+
const index = newExpandedKeys.indexOf(eventKey)
161+
162+
if (expanded && index >= 0) {
163+
newExpandedKeys.splice(index, 1)
164+
} else if (!expanded && index === -1) {
165+
newExpandedKeys.push(eventKey)
166+
}
167+
168+
this.setUncontrolledState({
169+
_expandedKeys: newExpandedKeys,
170+
})
171+
this.$emit('expand', newExpandedKeys, {
172+
expanded: !expanded,
173+
node,
174+
nativeEvent: event.nativeEvent,
175+
})
176+
},
177+
178+
setUncontrolledState (state) {
179+
const newState = omit(state, Object.keys(getOptionProps(this)).map(p => `_${p}`))
180+
if (Object.keys(newState).length) {
181+
this.setState(newState)
182+
}
183+
},
184+
},
185+
186+
render () {
187+
const { prefixCls, ...props } = getOptionProps(this)
188+
const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data
189+
const treeProps = {
190+
props: {
191+
icon: getIcon,
192+
...props,
193+
prefixCls,
194+
expandedKeys,
195+
selectedKeys,
196+
},
197+
class: `${prefixCls}-directory`,
198+
select: this.onSelect,
199+
click: this.onClick,
200+
doubleclick: this.onDoubleClick,
201+
expand: this.onExpand,
202+
}
203+
return (
204+
<Tree {...treeProps}>{this.$slots.default}</Tree>
205+
)
206+
},
207+
}

components/tree/Tree.jsx

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import warning from 'warning'
2+
import { Tree as VcTree, TreeNode } from '../vc-tree'
3+
import animation from '../_util/openAnimation'
4+
import PropTypes from '../_util/vue-types'
5+
import { initDefaultProps, getOptionProps } from '../_util/props-util'
6+
7+
function TreeProps () {
8+
return {
9+
showLine: PropTypes.bool,
10+
/** 是否支持多选 */
11+
multiple: PropTypes.bool,
12+
/** 是否自动展开父节点 */
13+
autoExpandParent: PropTypes.bool,
14+
/** checkable状态下节点选择完全受控(父子节点选中状态不再关联)*/
15+
checkStrictly: PropTypes.bool,
16+
/** 是否支持选中 */
17+
checkable: PropTypes.bool,
18+
/** 是否禁用树 */
19+
disabled: PropTypes.bool,
20+
/** 默认展开所有树节点 */
21+
defaultExpandAll: PropTypes.bool,
22+
/** 默认展开对应树节点 */
23+
defaultExpandParent: PropTypes.bool,
24+
/** 默认展开指定的树节点 */
25+
defaultExpandedKeys: PropTypes.arrayOf(String),
26+
/** (受控)展开指定的树节点 */
27+
expandedKeys: PropTypes.arrayOf(String),
28+
/** (受控)选中复选框的树节点 */
29+
checkedKeys: PropTypes.oneOfType(
30+
[
31+
PropTypes.arrayOf(PropTypes.string),
32+
PropTypes.shape({
33+
checked: PropTypes.arrayOf(String),
34+
halfChecked: PropTypes.arrayOf(String),
35+
}).loose,
36+
]
37+
),
38+
/** 默认选中复选框的树节点 */
39+
defaultCheckedKeys: PropTypes.arrayOf(String),
40+
/** (受控)设置选中的树节点 */
41+
selectedKeys: PropTypes.arrayOf(String),
42+
/** 默认选中的树节点 */
43+
defaultSelectedKeys: PropTypes.arrayOf(String),
44+
selectable: PropTypes.bool,
45+
/** 展开/收起节点时触发 */
46+
// onExpand: (expandedKeys: string[], info: AntTreeNodeExpandedEvent) => void | PromiseLike<any>,
47+
/** 点击复选框触发 */
48+
// onCheck: (checkedKeys: string[] | { checked: string[]; halfChecked: string[] }, e: AntTreeNodeCheckedEvent) => void,
49+
/** 点击树节点触发 */
50+
// onSelect: (selectedKeys: string[], e: AntTreeNodeSelectedEvent) => void,
51+
/** 单击树节点触发 */
52+
// onClick: (e: React.MouseEvent<HTMLElement>, node: AntTreeNode) => void,
53+
/** 双击树节点触发 */
54+
// onDoubleClick: (e: React.MouseEvent<HTMLElement>, node: AntTreeNode) => void,
55+
/** filter some AntTreeNodes as you need. it should return true */
56+
filterAntTreeNode: PropTypes.func,
57+
/** 异步加载数据 */
58+
loadData: PropTypes.func,
59+
loadedKeys: PropTypes.arrayOf(String),
60+
// onLoaded: (loadedKeys: string[], info: { event: 'load', node: AntTreeNode; }) => void,
61+
/** 响应右键点击 */
62+
// onRightClick: (options: AntTreeNodeMouseEvent) => void,
63+
/** 设置节点可拖拽(IE>8)*/
64+
draggable: PropTypes.bool,
65+
// /** 开始拖拽时调用 */
66+
// onDragStart: (options: AntTreeNodeMouseEvent) => void,
67+
// /** dragenter 触发时调用 */
68+
// onDragEnter: (options: AntTreeNodeMouseEvent) => void,
69+
// /** dragover 触发时调用 */
70+
// onDragOver: (options: AntTreeNodeMouseEvent) => void,
71+
// /** dragleave 触发时调用 */
72+
// onDragLeave: (options: AntTreeNodeMouseEvent) => void,
73+
// /** drop 触发时调用 */
74+
// onDrop: (options: AntTreeNodeMouseEvent) => void,
75+
showIcon: PropTypes.bool,
76+
icon: PropTypes.func,
77+
prefixCls: PropTypes.string,
78+
filterTreeNode: PropTypes.func,
79+
openAnimation: PropTypes.any,
80+
treeNodes: PropTypes.array,
81+
treeData: PropTypes.array,
82+
}
83+
}
84+
85+
export { TreeProps }
86+
87+
export default {
88+
name: 'ATree',
89+
model: {
90+
prop: 'checkedKeys',
91+
event: 'check',
92+
},
93+
props: initDefaultProps(TreeProps(), {
94+
prefixCls: 'ant-tree',
95+
checkable: false,
96+
showIcon: false,
97+
openAnimation: {
98+
on: animation,
99+
props: { appear: null },
100+
},
101+
}),
102+
created () {
103+
warning(
104+
!('treeNodes' in getOptionProps(this)),
105+
'`treeNodes` is deprecated. please use treeData instead.'
106+
)
107+
},
108+
TreeNode,
109+
methods: {
110+
updataTreeData (treeData) {
111+
const { $slots, $scopedSlots } = this
112+
return treeData.map((item) => {
113+
const { children, on = {}, slots = {}, scopedSlots = {}, key, class: cls, style, ...restProps } = item
114+
const treeNodeProps = {
115+
...restProps,
116+
icon: restProps.icon ||
117+
$slots[slots.icon] ||
118+
($scopedSlots[scopedSlots.icon] && $scopedSlots[scopedSlots.icon]),
119+
title: restProps.title ||
120+
$slots[slots.title] ||
121+
($scopedSlots[scopedSlots.title] && $scopedSlots[scopedSlots.title])(item),
122+
dataRef: item,
123+
on,
124+
key,
125+
class: cls,
126+
style,
127+
}
128+
if (children) {
129+
return { ...treeNodeProps, children: this.updataTreeData(children) }
130+
}
131+
return treeNodeProps
132+
})
133+
},
134+
},
135+
render () {
136+
const props = getOptionProps(this)
137+
const { prefixCls, showIcon, treeNodes } = props
138+
const checkable = props.checkable
139+
let treeData = props.treeData || treeNodes
140+
if (treeData) {
141+
treeData = this.updataTreeData(treeData)
142+
}
143+
const vcTreeProps = {
144+
props: {
145+
...props,
146+
checkable: checkable ? <span class={`${prefixCls}-checkbox-inner`} /> : checkable,
147+
children: this.$slots.default || [],
148+
__propsSymbol__: Symbol(),
149+
},
150+
on: {
151+
...this.$listeners,
152+
},
153+
class: !showIcon && `${prefixCls}-icon-hide`,
154+
}
155+
if (treeData) {
156+
vcTreeProps.props.treeData = treeData
157+
}
158+
return (
159+
<VcTree {...vcTreeProps} />
160+
)
161+
},
162+
}

components/tree/demo/basic-controlled.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ basic controlled example
1818
v-model="checkedKeys"
1919
@select="onSelect"
2020
:selectedKeys="selectedKeys"
21-
:treeNodes="treeData"
21+
:treeData="treeData"
2222
/>
2323
</template>
2424
<script>
@@ -75,7 +75,7 @@ export default {
7575
},
7676
methods: {
7777
onExpand (expandedKeys) {
78-
console.log('onExpand', arguments)
78+
console.log('onExpand', expandedKeys)
7979
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
8080
// or, you can remove all expanded children keys.
8181
this.expandedKeys = expandedKeys

components/tree/demo/basic.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The most basic usage, tell you how to use checkable, selectable, disabled, defau
1212
<template>
1313
<a-tree
1414
checkable
15-
:treeNodes="treeData"
15+
:treeData="treeData"
1616
:defaultExpandedKeys="['0-0-0', '0-0-1']"
1717
:defaultSelectedKeys="['0-0-0', '0-0-1']"
1818
:defaultCheckedKeys="['0-0-0', '0-0-1']"

0 commit comments

Comments
 (0)