feat: update tree
parent
10b25b0ec7
commit
61500001df
|
@ -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;
|
||||||
|
|
|
@ -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>;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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} />;
|
||||||
},
|
},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue