feat: update tree

pull/2682/head
tanjinzhou 2020-07-16 18:31:20 +08:00
parent 10b25b0ec7
commit 61500001df
10 changed files with 146 additions and 152 deletions

View File

@ -113,6 +113,7 @@ const getAllChildren = ele => {
return ele.children || componentOptions.children || []; return ele.children || componentOptions.children || [];
}; };
const getSlotOptions = ele => { const getSlotOptions = ele => {
throw Error('使用 .type 直接取值');
if (ele.fnOptions) { if (ele.fnOptions) {
// 函数式组件 // 函数式组件
return ele.fnOptions; return ele.fnOptions;

View File

@ -1,10 +1,11 @@
import { inject } from 'vue';
import omit from 'omit.js'; import omit from 'omit.js';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import FolderOpenOutlined from '@ant-design/icons-vue/FolderOpenOutlined'; import FolderOpenOutlined from '@ant-design/icons-vue/FolderOpenOutlined';
import FolderOutlined from '@ant-design/icons-vue/FolderOutlined'; import FolderOutlined from '@ant-design/icons-vue/FolderOutlined';
import FileOutlined from '@ant-design/icons-vue/FileOutlined'; import FileOutlined from '@ant-design/icons-vue/FileOutlined';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import warning from '../_util/warning'; import classNames from 'classnames';
import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util'; import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util';
import Tree, { TreeProps } from './Tree'; import Tree, { TreeProps } from './Tree';
import { import {
@ -14,12 +15,7 @@ import {
getFullKeyListByTreeData, getFullKeyListByTreeData,
} from './util'; } from './util';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { import { initDefaultProps, getOptionProps, getComponent, getSlot } from '../_util/props-util';
initDefaultProps,
getOptionProps,
getListeners,
getComponentFromProp,
} from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider'; import { ConfigConsumerProps } from '../config-provider';
// export type ExpandAction = false | 'click' | 'dblclick'; export interface // export type ExpandAction = false | 'click' | 'dblclick'; export interface
@ -27,7 +23,7 @@ import { ConfigConsumerProps } from '../config-provider';
// export interface DirectoryTreeState { expandedKeys?: string[]; // export interface DirectoryTreeState { expandedKeys?: string[];
// selectedKeys?: string[]; } // selectedKeys?: string[]; }
function getIcon(props, h) { function getIcon(props) {
const { isLeaf, expanded } = props; const { isLeaf, expanded } = props;
if (isLeaf) { if (isLeaf) {
return <FileOutlined />; return <FileOutlined />;
@ -38,10 +34,11 @@ function getIcon(props, h) {
export default { export default {
name: 'ADirectoryTree', name: 'ADirectoryTree',
mixins: [BaseMixin], mixins: [BaseMixin],
model: { inheritAttrs: false,
prop: 'checkedKeys', // model: {
event: 'check', // prop: 'checkedKeys',
}, // event: 'check',
// },
props: initDefaultProps( props: initDefaultProps(
{ {
...TreeProps(), ...TreeProps(),
@ -52,14 +49,10 @@ export default {
expandAction: 'click', expandAction: 'click',
}, },
), ),
setup() {
// state: DirectoryTreeState; onDebounceExpand: (event, node: AntTreeNode) => return {
// void; // Shift click usage lastSelectedKey?: string; cachedSelectedKeys?: configProvider: inject('configProvider', ConfigConsumerProps),
// string[]; };
inject: {
configProvider: {
default: () => ConfigConsumerProps,
},
}, },
data() { data() {
const props = getOptionProps(this); const props = getOptionProps(this);
@ -83,6 +76,7 @@ export default {
} }
this.onDebounceExpand = debounce(this.expandFolderNode, 200, { leading: true }); this.onDebounceExpand = debounce(this.expandFolderNode, 200, { leading: true });
this.children = null;
return { return {
_selectedKeys: [], _selectedKeys: [],
_expandedKeys: [], _expandedKeys: [],
@ -130,7 +124,7 @@ export default {
onSelect(keys, event) { onSelect(keys, event) {
const { multiple } = this.$props; const { multiple } = this.$props;
const children = this.$slots.default || []; const children = this.children || [];
const { _expandedKeys: expandedKeys = [] } = this.$data; const { _expandedKeys: expandedKeys = [] } = this.$data;
const { node, nativeEvent } = event; const { node, nativeEvent } = event;
const { eventKey = '' } = node; const { eventKey = '' } = node;
@ -178,6 +172,9 @@ export default {
this.setUncontrolledState(newState); this.setUncontrolledState(newState);
}, },
setTreeRef(node) {
this.tree = node;
},
expandFolderNode(event, node) { expandFolderNode(event, node) {
const { isLeaf } = node; const { isLeaf } = node;
@ -186,9 +183,9 @@ export default {
return; return;
} }
if (this.$refs.tree.$refs.tree) { if (this.tree.tree) {
// Get internal vc-tree // Get internal vc-tree
const internalTree = this.$refs.tree.$refs.tree; const internalTree = this.tree.tree;
// Call internal rc-tree expand function // Call internal rc-tree expand function
// https://github.com/ant-design/ant-design/issues/12567 // https://github.com/ant-design/ant-design/issues/12567
@ -208,31 +205,28 @@ export default {
}, },
render() { render() {
this.children = getSlot(this);
const { prefixCls: customizePrefixCls, ...props } = getOptionProps(this); const { prefixCls: customizePrefixCls, ...props } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('tree', customizePrefixCls); const prefixCls = getPrefixCls('tree', customizePrefixCls);
const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data; const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data;
const listeners = getListeners(this); const { class: className, ...restAttrs } = this.$attrs;
warning(!listeners.doubleclick, '`doubleclick` is deprecated. please use `dblclick` instead.'); const connectClassName = classNames(`${prefixCls}-directory`, className);
const treeProps = { const treeProps = {
props: { icon: getIcon,
icon: getIcon, ...props,
...props, ...omit(restAttrs, ['onUpdate:selectedKeys']),
prefixCls, prefixCls,
expandedKeys, expandedKeys,
selectedKeys, selectedKeys,
switcherIcon: getComponentFromProp(this, 'switcherIcon'), switcherIcon: getComponent(this, 'switcherIcon'),
}, ref: this.setTreeRef,
ref: 'tree', class: connectClassName,
class: `${prefixCls}-directory`, onSelect: this.onSelect,
on: { onClick: this.onClick,
...omit(listeners, ['update:selectedKeys']), onDblclick: this.onDoubleClick,
select: this.onSelect, onExpand: this.onExpand,
click: this.onClick,
dblclick: this.onDoubleClick,
expand: this.onExpand,
},
}; };
return <Tree {...treeProps}>{this.$slots.default}</Tree>; return <Tree {...treeProps}>{this.children}</Tree>;
}, },
}; };

View File

@ -1,4 +1,5 @@
import warning from 'warning'; import { inject } from 'vue';
import classNames from 'classnames';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'; import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import FileOutlined from '@ant-design/icons-vue/FileOutlined'; import FileOutlined from '@ant-design/icons-vue/FileOutlined';
import CaretDownFilled from '@ant-design/icons-vue/CaretDownFilled'; import CaretDownFilled from '@ant-design/icons-vue/CaretDownFilled';
@ -7,13 +8,7 @@ import PlusSquareOutlined from '@ant-design/icons-vue/PlusSquareOutlined';
import { Tree as VcTree, TreeNode } from '../vc-tree'; import { Tree as VcTree, TreeNode } from '../vc-tree';
import animation from '../_util/openAnimation'; import animation from '../_util/openAnimation';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { import { initDefaultProps, getOptionProps, getComponent, getSlot } from '../_util/props-util';
initDefaultProps,
getOptionProps,
filterEmpty,
getComponentFromProp,
getListeners,
} from '../_util/props-util';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import { ConfigConsumerProps } from '../config-provider'; import { ConfigConsumerProps } from '../config-provider';
@ -89,7 +84,6 @@ function TreeProps() {
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
filterTreeNode: PropTypes.func, filterTreeNode: PropTypes.func,
openAnimation: PropTypes.any, openAnimation: PropTypes.any,
treeNodes: PropTypes.array,
treeData: PropTypes.array, treeData: PropTypes.array,
/** /**
* @default{title,key,children} * @default{title,key,children}
@ -104,27 +98,20 @@ export { TreeProps };
export default { export default {
name: 'ATree', name: 'ATree',
model: { inheritAttrs: false,
prop: 'checkedKeys',
event: 'check',
},
props: initDefaultProps(TreeProps(), { props: initDefaultProps(TreeProps(), {
checkable: false, checkable: false,
showIcon: false, showIcon: false,
openAnimation: { openAnimation: {
on: animation, ...animation,
props: { appear: null }, appear: null,
}, },
blockNode: false, blockNode: false,
}), }),
inject: { setup() {
configProvider: { default: () => ConfigConsumerProps }, return {
}, configProvider: inject('configProvider', ConfigConsumerProps),
created() { };
warning(
!('treeNodes' in getOptionProps(this)),
'`treeNodes` is deprecated. please use treeData instead.',
);
}, },
TreeNode, TreeNode,
methods: { methods: {
@ -146,34 +133,32 @@ export default {
}); });
} }
return showLine ? ( return showLine ? (
expanded ? expanded ? (
<MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} /> : <MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
) : (
<PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} /> <PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
)
) : ( ) : (
<CaretDownFilled class={switcherCls} /> <CaretDownFilled class={switcherCls} />
); );
}, },
updateTreeData(treeData) { updateTreeData(treeData) {
const { $slots, $scopedSlots } = this; const { $slots } = this;
const defaultFields = { children: 'children', title: 'title', key: 'key' }; const defaultFields = { children: 'children', title: 'title', key: 'key' };
const replaceFields = { ...defaultFields, ...this.$props.replaceFields }; const replaceFields = { ...defaultFields, ...this.$props.replaceFields };
return treeData.map(item => { return treeData.map(item => {
const key = item[replaceFields.key]; const key = item[replaceFields.key];
const children = item[replaceFields.children]; const children = item[replaceFields.children];
const { on = {}, slots = {}, scopedSlots = {}, class: cls, style, ...restProps } = item; const { slots = {}, scopedSlots = {}, class: cls, style, ...restProps } = item;
const treeNodeProps = { const treeNodeProps = {
...restProps, ...restProps,
icon: $scopedSlots[scopedSlots.icon] || $slots[slots.icon] || restProps.icon, icon: $slots[scopedSlots.icon] || $slots[slots.icon] || restProps.icon,
switcherIcon: switcherIcon:
$scopedSlots[scopedSlots.switcherIcon] || $slots[scopedSlots.switcherIcon] ||
$slots[slots.switcherIcon] || $slots[slots.switcherIcon] ||
restProps.switcherIcon, restProps.switcherIcon,
title: title: $slots[scopedSlots.title] || $slots[slots.title] || restProps[replaceFields.title],
$scopedSlots[scopedSlots.title] ||
$slots[slots.title] ||
restProps[replaceFields.title],
dataRef: item, dataRef: item,
on,
key, key,
class: cls, class: cls,
style, style,
@ -184,37 +169,38 @@ export default {
return treeNodeProps; return treeNodeProps;
}); });
}, },
setTreeRef(node) {
this.tree = node;
},
}, },
render() { render() {
const props = getOptionProps(this); const props = getOptionProps(this);
const { $slots, $scopedSlots } = this;
const { prefixCls: customizePrefixCls, showIcon, treeNodes, blockNode } = props; const { prefixCls: customizePrefixCls, showIcon, treeNodes, blockNode } = props;
const getPrefixCls = this.configProvider.getPrefixCls; const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('tree', customizePrefixCls); const prefixCls = getPrefixCls('tree', customizePrefixCls);
const switcherIcon = getComponentFromProp(this, 'switcherIcon'); const switcherIcon = getComponent(this, 'switcherIcon');
const checkable = props.checkable; const checkable = props.checkable;
let treeData = props.treeData || treeNodes; let treeData = props.treeData || treeNodes;
if (treeData) { if (treeData) {
treeData = this.updateTreeData(treeData); treeData = this.updateTreeData(treeData);
} }
const { class: className, ...restAttrs } = this.$attrs;
const vcTreeProps = { const vcTreeProps = {
props: { ...props,
...props, prefixCls,
prefixCls, checkable: checkable ? <span class={`${prefixCls}-checkbox-inner`} /> : checkable,
checkable: checkable ? <span class={`${prefixCls}-checkbox-inner`} /> : checkable, children: getSlot(this),
children: filterEmpty($scopedSlots.default ? $scopedSlots.default() : $slots.default), __propsSymbol__: Symbol(),
__propsSymbol__: Symbol(), switcherIcon: nodeProps => this.renderSwitcherIcon(prefixCls, switcherIcon, nodeProps),
switcherIcon: nodeProps => this.renderSwitcherIcon(prefixCls, switcherIcon, nodeProps), ref: this.setTreeRef,
}, ...restAttrs,
on: getListeners(this), class: classNames(className, {
ref: 'tree',
class: {
[`${prefixCls}-icon-hide`]: !showIcon, [`${prefixCls}-icon-hide`]: !showIcon,
[`${prefixCls}-block-node`]: blockNode, [`${prefixCls}-block-node`]: blockNode,
}, }),
}; };
if (treeData) { if (treeData) {
vcTreeProps.props.treeData = treeData; vcTreeProps.treeData = treeData;
} }
return <VcTree {...vcTreeProps} />; return <VcTree {...vcTreeProps} />;
}, },

View File

@ -1,15 +1,13 @@
import Tree from './Tree'; import Tree from './Tree';
import DirectoryTree from './DirectoryTree'; import DirectoryTree from './DirectoryTree';
import Base from '../base';
Tree.TreeNode.name = 'ATreeNode'; Tree.TreeNode.name = 'ATreeNode';
Tree.DirectoryTree = DirectoryTree; Tree.DirectoryTree = DirectoryTree;
/* istanbul ignore next */ /* istanbul ignore next */
Tree.install = function(Vue) { Tree.install = function(app) {
Vue.use(Base); app.component(Tree.name, Tree);
Vue.component(Tree.name, Tree); app.component(Tree.TreeNode.name, Tree.TreeNode);
Vue.component(Tree.TreeNode.name, Tree.TreeNode); app.component(DirectoryTree.name, DirectoryTree);
Vue.component(DirectoryTree.name, DirectoryTree);
}; };
export default Tree; export default Tree;

View File

@ -13,7 +13,7 @@ function traverseNodesKey(rootChildren, callback) {
function processNode(node) { function processNode(node) {
const { key } = node; const { key } = node;
const children = getSlots(node).default; const children = getSlots(node);
if (callback(key, node) !== false) { if (callback(key, node) !== false) {
traverseNodesKey(typeof children === 'function' ? children() : children, callback); traverseNodesKey(typeof children === 'function' ? children() : children, callback);
} }

View File

@ -4,7 +4,6 @@ import warning from 'warning';
import { hasProp, initDefaultProps, getOptionProps, getSlots } from '../../_util/props-util'; import { hasProp, initDefaultProps, getOptionProps, getSlots } from '../../_util/props-util';
import { cloneElement } from '../../_util/vnode'; import { cloneElement } from '../../_util/vnode';
import BaseMixin from '../../_util/BaseMixin'; import BaseMixin from '../../_util/BaseMixin';
import proxyComponent from '../../_util/proxyComponent';
import { import {
convertTreeToEntities, convertTreeToEntities,
convertDataToTree, convertDataToTree,
@ -20,6 +19,7 @@ import {
mapChildren, mapChildren,
conductCheck, conductCheck,
warnOnlyTreeNode, warnOnlyTreeNode,
getDataAndAria,
} from './util'; } from './util';
/** /**
@ -39,6 +39,7 @@ function getWatch(keys = []) {
const Tree = { const Tree = {
name: 'Tree', name: 'Tree',
inheritAttrs: false,
mixins: [BaseMixin], mixins: [BaseMixin],
props: initDefaultProps( props: initDefaultProps(
{ {
@ -85,7 +86,7 @@ const Tree = {
openTransitionName: PropTypes.string, openTransitionName: PropTypes.string,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
switcherIcon: PropTypes.any, switcherIcon: PropTypes.any,
_propsSymbol: PropTypes.any, __propsSymbol__: PropTypes.any,
}, },
{ {
prefixCls: 'rc-tree', prefixCls: 'rc-tree',
@ -169,7 +170,7 @@ const Tree = {
// Check if `treeData` or `children` changed and save into the state. // Check if `treeData` or `children` changed and save into the state.
if (needSync('treeData')) { if (needSync('treeData')) {
treeNode = convertDataToTree(this.$createElement, props.treeData); treeNode = convertDataToTree(props.treeData);
} else if (needSync('children')) { } else if (needSync('children')) {
treeNode = props.children; treeNode = props.children;
} }
@ -248,7 +249,7 @@ const Tree = {
onNodeDragStart(event, node) { onNodeDragStart(event, node) {
const { _expandedKeys } = this.$data; const { _expandedKeys } = this.$data;
const { eventKey } = node; const { eventKey } = node;
const children = getSlots(node).default; const children = getSlots(node);
this.dragNode = node; this.dragNode = node;
this.setState({ this.setState({
@ -272,7 +273,7 @@ const Tree = {
const { _expandedKeys: expandedKeys } = this.$data; const { _expandedKeys: expandedKeys } = this.$data;
const { pos, eventKey } = node; const { pos, eventKey } = node;
if (!this.dragNode || !node.$refs.selectHandle) return; if (!this.dragNode || !node.selectHandle) return;
const dropPosition = calcDropPosition(event, node); const dropPosition = calcDropPosition(event, node);
@ -319,7 +320,7 @@ const Tree = {
const { eventKey } = node; const { eventKey } = node;
const { _dragOverNodeKey, _dropPosition } = this.$data; const { _dragOverNodeKey, _dropPosition } = this.$data;
// Update drag position // Update drag position
if (this.dragNode && eventKey === _dragOverNodeKey && node.$refs.selectHandle) { if (this.dragNode && eventKey === _dragOverNodeKey && node.selectHandle) {
const dropPosition = calcDropPosition(event, node); const dropPosition = calcDropPosition(event, node);
if (dropPosition === _dropPosition) return; if (dropPosition === _dropPosition) return;
@ -479,6 +480,7 @@ const Tree = {
_halfCheckedKeys: halfCheckedKeys, _halfCheckedKeys: halfCheckedKeys,
}); });
} }
this.$emit('update:checkedKeys', checkedObj);
this.__emit('check', checkedObj, eventObj); this.__emit('check', checkedObj, eventObj);
}, },
onNodeLoad(treeNode) { onNodeLoad(treeNode) {
@ -637,21 +639,19 @@ const Tree = {
} }
return cloneElement(child, { return cloneElement(child, {
props: { eventKey: key,
eventKey: key, expanded: expandedKeys.indexOf(key) !== -1,
expanded: expandedKeys.indexOf(key) !== -1, selected: selectedKeys.indexOf(key) !== -1,
selected: selectedKeys.indexOf(key) !== -1, loaded: loadedKeys.indexOf(key) !== -1,
loaded: loadedKeys.indexOf(key) !== -1, loading: loadingKeys.indexOf(key) !== -1,
loading: loadingKeys.indexOf(key) !== -1, checked: this.isKeyChecked(key),
checked: this.isKeyChecked(key), halfChecked: halfCheckedKeys.indexOf(key) !== -1,
halfChecked: halfCheckedKeys.indexOf(key) !== -1, pos,
pos,
// [Legacy] Drag props // [Legacy] Drag props
dragOver: dragOverNodeKey === key && dropPosition === 0, dragOver: dragOverNodeKey === key && dropPosition === 0,
dragOverGapTop: dragOverNodeKey === key && dropPosition === -1, dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1, dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1,
},
key, key,
}); });
}, },
@ -660,12 +660,15 @@ const Tree = {
render() { render() {
const { _treeNode: treeNode } = this.$data; const { _treeNode: treeNode } = this.$data;
const { prefixCls, focusable, showLine, tabIndex = 0 } = this.$props; const { prefixCls, focusable, showLine, tabIndex = 0 } = this.$props;
const domProps = getDataAndAria({ ...this.$props, ...this.$attrs });
const { class: className, style } = this.$attrs;
return ( return (
<ul <ul
class={classNames(prefixCls, { {...domProps}
class={classNames(prefixCls, className, {
[`${prefixCls}-show-line`]: showLine, [`${prefixCls}-show-line`]: showLine,
})} })}
style={style}
role="tree" role="tree"
unselectable="on" unselectable="on"
tabIndex={focusable ? tabIndex : null} tabIndex={focusable ? tabIndex : null}
@ -678,4 +681,4 @@ const Tree = {
export { Tree }; export { Tree };
export default proxyComponent(Tree); export default Tree;

View File

@ -1,7 +1,8 @@
import { inject, provide } from 'vue';
import PropTypes from '../../_util/vue-types'; import PropTypes from '../../_util/vue-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { getNodeChildren, mapChildren, warnOnlyTreeNode } from './util'; import { getNodeChildren, mapChildren, warnOnlyTreeNode, getDataAndAria } from './util';
import { initDefaultProps, filterEmpty, getComponentFromProp } from '../../_util/props-util'; import { initDefaultProps, filterEmpty, getComponent } from '../../_util/props-util';
import BaseMixin from '../../_util/BaseMixin'; import BaseMixin from '../../_util/BaseMixin';
import getTransitionProps from '../../_util/getTransitionProps'; import getTransitionProps from '../../_util/getTransitionProps';
@ -13,6 +14,7 @@ const defaultTitle = '---';
const TreeNode = { const TreeNode = {
name: 'TreeNode', name: 'TreeNode',
inheritAttrs: false,
mixins: [BaseMixin], mixins: [BaseMixin],
__ANT_TREE_NODE: true, __ANT_TREE_NODE: true,
props: initDefaultProps( props: initDefaultProps(
@ -56,16 +58,19 @@ const TreeNode = {
dragNodeHighlight: false, dragNodeHighlight: false,
}; };
}, },
setup() {
return {
vcTree: inject('vcTree', {}),
vcTreeNode: inject('vcTreeNode', {}),
};
},
inject: { inject: {
vcTree: { default: () => ({}) }, vcTree: { default: () => ({}) },
vcTreeNode: { default: () => ({}) }, vcTreeNode: { default: () => ({}) },
}, },
provide() { created() {
return { provide('vcTreeNode', this);
vcTreeNode: this,
};
}, },
// Isomorphic needn't load data in server side // Isomorphic needn't load data in server side
mounted() { mounted() {
const { const {
@ -234,6 +239,10 @@ const TreeNode = {
} = this; } = this;
onNodeExpand(e, this); onNodeExpand(e, this);
}, },
// Drag usage
setSelectHandle(node) {
this.selectHandle = node;
},
getNodeChildren() { getNodeChildren() {
const { const {
@ -336,8 +345,8 @@ const TreeNode = {
vcTree: { prefixCls }, vcTree: { prefixCls },
} = this; } = this;
const switcherIcon = const switcherIcon =
getComponentFromProp(this, 'switcherIcon', {}, false) || getComponent(this, 'switcherIcon', {}, false) ||
getComponentFromProp(this.vcTree, 'switcherIcon', {}, false); getComponent(this.vcTree, 'switcherIcon', {}, false);
if (this.isLeaf2()) { if (this.isLeaf2()) {
return ( return (
<span <span
@ -413,14 +422,14 @@ const TreeNode = {
}, },
// Icon + Title // Icon + Title
renderSelector(h) { renderSelector() {
const { selected, loading, dragNodeHighlight } = this; const { selected, loading, dragNodeHighlight } = this;
const icon = getComponentFromProp(this, 'icon', {}, false); const icon = getComponent(this, 'icon', {}, false);
const { const {
vcTree: { prefixCls, showIcon, icon: treeIcon, draggable, loadData }, vcTree: { prefixCls, showIcon, icon: treeIcon, draggable, loadData },
} = this; } = this;
const disabled = this.isDisabled(); const disabled = this.isDisabled();
const title = getComponentFromProp(this, 'title', {}, false); const title = getComponent(this, 'title', {}, false);
const wrapClass = `${prefixCls}-node-content-wrapper`; const wrapClass = `${prefixCls}-node-content-wrapper`;
// Icon - Still show loading icon when loading without showIcon // Icon - Still show loading icon when loading without showIcon
@ -431,7 +440,7 @@ const TreeNode = {
$icon = currentIcon ? ( $icon = currentIcon ? (
<span class={classNames(`${prefixCls}-iconEle`, `${prefixCls}-icon__customize`)}> <span class={classNames(`${prefixCls}-iconEle`, `${prefixCls}-icon__customize`)}>
{typeof currentIcon === 'function' {typeof currentIcon === 'function'
? currentIcon({ ...this.$props, ...this.$props.dataRef }, h) ? currentIcon({ ...this.$props, ...this.$props.dataRef })
: currentIcon} : currentIcon}
</span> </span>
) : ( ) : (
@ -445,17 +454,16 @@ const TreeNode = {
let $title = currentTitle ? ( let $title = currentTitle ? (
<span class={`${prefixCls}-title`}> <span class={`${prefixCls}-title`}>
{typeof currentTitle === 'function' {typeof currentTitle === 'function'
? currentTitle({ ...this.$props, ...this.$props.dataRef }, h) ? currentTitle({ ...this.$props, ...this.$props.dataRef })
: currentTitle} : currentTitle}
</span> </span>
) : ( ) : (
<span class={`${prefixCls}-title`}>{defaultTitle}</span> <span class={`${prefixCls}-title`}>{defaultTitle}</span>
); );
return ( return (
<span <span
key="selector" key="selector"
ref="selectHandle" ref={this.setSelectHandle}
title={typeof title === 'string' ? title : ''} title={typeof title === 'string' ? title : ''}
class={classNames( class={classNames(
`${wrapClass}`, `${wrapClass}`,
@ -489,8 +497,7 @@ const TreeNode = {
if (openTransitionName) { if (openTransitionName) {
animProps = getTransitionProps(openTransitionName); animProps = getTransitionProps(openTransitionName);
} else if (typeof openAnimation === 'object') { } else if (typeof openAnimation === 'object') {
animProps = { ...openAnimation }; animProps = { ...openAnimation, css: false, ...animProps };
animProps.props = { css: false, ...animProps.props };
} }
// Children TreeNode // Children TreeNode
@ -520,7 +527,7 @@ const TreeNode = {
}, },
}, },
render(h) { render() {
const { const {
dragOver, dragOver,
dragOverGapTop, dragOverGapTop,
@ -536,9 +543,12 @@ const TreeNode = {
vcTree: { prefixCls, filterTreeNode, draggable }, vcTree: { prefixCls, filterTreeNode, draggable },
} = this; } = this;
const disabled = this.isDisabled(); const disabled = this.isDisabled();
const dataOrAriaAttributeProps = getDataAndAria({ ...this.$props, ...this.$attrs });
const { class: className, style } = this.$attrs;
return ( return (
<li <li
class={{ class={{
className,
[`${prefixCls}-treenode-disabled`]: disabled, [`${prefixCls}-treenode-disabled`]: disabled,
[`${prefixCls}-treenode-switcher-${expanded ? 'open' : 'close'}`]: !isLeaf, [`${prefixCls}-treenode-switcher-${expanded ? 'open' : 'close'}`]: !isLeaf,
[`${prefixCls}-treenode-checkbox-checked`]: checked, [`${prefixCls}-treenode-checkbox-checked`]: checked,
@ -550,16 +560,18 @@ const TreeNode = {
'drag-over-gap-bottom': !disabled && dragOverGapBottom, 'drag-over-gap-bottom': !disabled && dragOverGapBottom,
'filter-node': filterTreeNode && filterTreeNode(this), 'filter-node': filterTreeNode && filterTreeNode(this),
}} }}
style={style}
role="treeitem" role="treeitem"
onDragenter={draggable ? this.onDragEnter : noop} onDragenter={draggable ? this.onDragEnter : noop}
onDragover={draggable ? this.onDragOver : noop} onDragover={draggable ? this.onDragOver : noop}
onDragleave={draggable ? this.onDragLeave : noop} onDragleave={draggable ? this.onDragLeave : noop}
onDrop={draggable ? this.onDrop : noop} onDrop={draggable ? this.onDrop : noop}
onDragend={draggable ? this.onDragEnd : noop} onDragend={draggable ? this.onDragEnd : noop}
{...dataOrAriaAttributeProps}
> >
{this.renderSwitcher()} {this.renderSwitcher()}
{this.renderCheckbox()} {this.renderCheckbox()}
{this.renderSelector(h)} {this.renderSelector()}
{this.renderChildren()} {this.renderChildren()}
</li> </li>
); );

View File

@ -1,8 +1,7 @@
/* eslint no-loop-func: 0*/ /* eslint no-loop-func: 0*/
import warning from 'warning'; import warning from 'warning';
import omit from 'omit.js';
import TreeNode from './TreeNode'; import TreeNode from './TreeNode';
import { getSlotOptions, getOptionProps } from '../../_util/props-util'; import { getOptionProps } from '../../_util/props-util';
const DRAG_SIDE_RANGE = 0.25; const DRAG_SIDE_RANGE = 0.25;
const DRAG_MIN_GAP = 2; const DRAG_MIN_GAP = 2;
@ -41,7 +40,7 @@ export function getPosition(level, index) {
} }
export function isTreeNode(node) { export function isTreeNode(node) {
return getSlotOptions(node).isTreeNode; return typeof node.type === 'object' && node.type.isTreeNode;
} }
export function getNodeChildren(children = []) { export function getNodeChildren(children = []) {
@ -55,7 +54,7 @@ export function isCheckDisabled(node) {
export function traverseTreeNodes(treeNodes, callback) { export function traverseTreeNodes(treeNodes, callback) {
function processNode(node, index, parent) { function processNode(node, index, parent) {
const children = node ? node.componentOptions.children : treeNodes; const children = node ? node.children?.default() : treeNodes;
const pos = node ? getPosition(parent.pos, index) : 0; const pos = node ? getPosition(parent.pos, index) : 0;
// Filter children // Filter children
@ -111,7 +110,7 @@ export function getDragNodesKeys(treeNodes, node) {
export function calcDropPosition(event, treeNode) { export function calcDropPosition(event, treeNode) {
const { clientY } = event; const { clientY } = event;
const { top, bottom, height } = treeNode.$refs.selectHandle.getBoundingClientRect(); const { top, bottom, height } = treeNode.selectHandle.getBoundingClientRect();
const des = Math.max(height * DRAG_SIDE_RANGE, DRAG_MIN_GAP); const des = Math.max(height * DRAG_SIDE_RANGE, DRAG_MIN_GAP);
if (clientY <= top + des) { if (clientY <= top + des) {
@ -156,20 +155,19 @@ export function calcSelectedKeys(selectedKeys, props) {
const internalProcessProps = (props = {}) => { const internalProcessProps = (props = {}) => {
return { return {
props: omit(props, ['on', 'key', 'class', 'className', 'style']), ...props,
on: props.on || {},
class: props.class || props.className, class: props.class || props.className,
style: props.style, style: props.style,
key: props.key, key: props.key,
}; };
}; };
export function convertDataToTree(h, treeData, processor) { export function convertDataToTree(treeData, processor) {
if (!treeData) return []; if (!treeData) return [];
const { processProps = internalProcessProps } = processor || {}; const { processProps = internalProcessProps } = processor || {};
const list = Array.isArray(treeData) ? treeData : [treeData]; const list = Array.isArray(treeData) ? treeData : [treeData];
return list.map(({ children, ...props }) => { return list.map(({ children, ...props }) => {
const childrenNodes = convertDataToTree(h, children, processor); const childrenNodes = convertDataToTree(children, processor);
return <TreeNode {...processProps(props)}>{childrenNodes}</TreeNode>; return <TreeNode {...processProps(props)}>{childrenNodes}</TreeNode>;
}); });
} }

View File

@ -4,7 +4,7 @@
</div> </div>
</template> </template>
<script> <script>
import demo from '../antdv-demo/docs/list/demo/grid'; import demo from '../antdv-demo/docs/tree/demo/basic';
export default { export default {
components: { components: {

View File

@ -27,6 +27,7 @@ import {
Collapse, Collapse,
Card, Card,
Avatar, Avatar,
Tree,
notification, notification,
message, message,
} from 'ant-design-vue'; } from 'ant-design-vue';
@ -74,4 +75,5 @@ app
.use(Collapse) .use(Collapse)
.use(Avatar) .use(Avatar)
.use(Card) .use(Card)
.use(Tree)
.mount('#app'); .mount('#app');