From 61500001df0193a58f64b418dd30d5ebb965e466 Mon Sep 17 00:00:00 2001
From: tanjinzhou <415800467@qq.com>
Date: Thu, 16 Jul 2020 18:31:20 +0800
Subject: [PATCH] feat: update tree
---
components/_util/props-util.js | 1 +
components/tree/DirectoryTree.jsx | 80 +++++++++++++--------------
components/tree/Tree.jsx | 84 ++++++++++++-----------------
components/tree/index.jsx | 10 ++--
components/tree/util.js | 2 +-
components/vc-tree/src/Tree.jsx | 49 +++++++++--------
components/vc-tree/src/TreeNode.jsx | 52 +++++++++++-------
components/vc-tree/src/util.js | 16 +++---
examples/App.vue | 2 +-
examples/index.js | 2 +
10 files changed, 146 insertions(+), 152 deletions(-)
diff --git a/components/_util/props-util.js b/components/_util/props-util.js
index 39a3536ac..6b2664509 100644
--- a/components/_util/props-util.js
+++ b/components/_util/props-util.js
@@ -113,6 +113,7 @@ const getAllChildren = ele => {
return ele.children || componentOptions.children || [];
};
const getSlotOptions = ele => {
+ throw Error('使用 .type 直接取值');
if (ele.fnOptions) {
// 函数式组件
return ele.fnOptions;
diff --git a/components/tree/DirectoryTree.jsx b/components/tree/DirectoryTree.jsx
index 681e08376..78f646278 100644
--- a/components/tree/DirectoryTree.jsx
+++ b/components/tree/DirectoryTree.jsx
@@ -1,10 +1,11 @@
+import { inject } from 'vue';
import omit from 'omit.js';
import debounce from 'lodash/debounce';
import FolderOpenOutlined from '@ant-design/icons-vue/FolderOpenOutlined';
import FolderOutlined from '@ant-design/icons-vue/FolderOutlined';
import FileOutlined from '@ant-design/icons-vue/FileOutlined';
import PropTypes from '../_util/vue-types';
-import warning from '../_util/warning';
+import classNames from 'classnames';
import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util';
import Tree, { TreeProps } from './Tree';
import {
@@ -14,12 +15,7 @@ import {
getFullKeyListByTreeData,
} from './util';
import BaseMixin from '../_util/BaseMixin';
-import {
- initDefaultProps,
- getOptionProps,
- getListeners,
- getComponentFromProp,
-} from '../_util/props-util';
+import { initDefaultProps, getOptionProps, getComponent, getSlot } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
// export type ExpandAction = false | 'click' | 'dblclick'; export interface
@@ -27,7 +23,7 @@ import { ConfigConsumerProps } from '../config-provider';
// export interface DirectoryTreeState { expandedKeys?: string[];
// selectedKeys?: string[]; }
-function getIcon(props, h) {
+function getIcon(props) {
const { isLeaf, expanded } = props;
if (isLeaf) {
return ;
@@ -38,10 +34,11 @@ function getIcon(props, h) {
export default {
name: 'ADirectoryTree',
mixins: [BaseMixin],
- model: {
- prop: 'checkedKeys',
- event: 'check',
- },
+ inheritAttrs: false,
+ // model: {
+ // prop: 'checkedKeys',
+ // event: 'check',
+ // },
props: initDefaultProps(
{
...TreeProps(),
@@ -52,14 +49,10 @@ export default {
expandAction: 'click',
},
),
-
- // state: DirectoryTreeState; onDebounceExpand: (event, node: AntTreeNode) =>
- // void; // Shift click usage lastSelectedKey?: string; cachedSelectedKeys?:
- // string[];
- inject: {
- configProvider: {
- default: () => ConfigConsumerProps,
- },
+ setup() {
+ return {
+ configProvider: inject('configProvider', ConfigConsumerProps),
+ };
},
data() {
const props = getOptionProps(this);
@@ -83,6 +76,7 @@ export default {
}
this.onDebounceExpand = debounce(this.expandFolderNode, 200, { leading: true });
+ this.children = null;
return {
_selectedKeys: [],
_expandedKeys: [],
@@ -130,7 +124,7 @@ export default {
onSelect(keys, event) {
const { multiple } = this.$props;
- const children = this.$slots.default || [];
+ const children = this.children || [];
const { _expandedKeys: expandedKeys = [] } = this.$data;
const { node, nativeEvent } = event;
const { eventKey = '' } = node;
@@ -178,6 +172,9 @@ export default {
this.setUncontrolledState(newState);
},
+ setTreeRef(node) {
+ this.tree = node;
+ },
expandFolderNode(event, node) {
const { isLeaf } = node;
@@ -186,9 +183,9 @@ export default {
return;
}
- if (this.$refs.tree.$refs.tree) {
+ if (this.tree.tree) {
// Get internal vc-tree
- const internalTree = this.$refs.tree.$refs.tree;
+ const internalTree = this.tree.tree;
// Call internal rc-tree expand function
// https://github.com/ant-design/ant-design/issues/12567
@@ -208,31 +205,28 @@ export default {
},
render() {
+ this.children = getSlot(this);
const { prefixCls: customizePrefixCls, ...props } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data;
- const listeners = getListeners(this);
- warning(!listeners.doubleclick, '`doubleclick` is deprecated. please use `dblclick` instead.');
+ const { class: className, ...restAttrs } = this.$attrs;
+ const connectClassName = classNames(`${prefixCls}-directory`, className);
const treeProps = {
- props: {
- icon: getIcon,
- ...props,
- prefixCls,
- expandedKeys,
- selectedKeys,
- switcherIcon: getComponentFromProp(this, 'switcherIcon'),
- },
- ref: 'tree',
- class: `${prefixCls}-directory`,
- on: {
- ...omit(listeners, ['update:selectedKeys']),
- select: this.onSelect,
- click: this.onClick,
- dblclick: this.onDoubleClick,
- expand: this.onExpand,
- },
+ icon: getIcon,
+ ...props,
+ ...omit(restAttrs, ['onUpdate:selectedKeys']),
+ prefixCls,
+ expandedKeys,
+ selectedKeys,
+ switcherIcon: getComponent(this, 'switcherIcon'),
+ ref: this.setTreeRef,
+ class: connectClassName,
+ onSelect: this.onSelect,
+ onClick: this.onClick,
+ onDblclick: this.onDoubleClick,
+ onExpand: this.onExpand,
};
- return {this.$slots.default};
+ return {this.children};
},
};
diff --git a/components/tree/Tree.jsx b/components/tree/Tree.jsx
index 5b24587b4..ec2b4bd7a 100644
--- a/components/tree/Tree.jsx
+++ b/components/tree/Tree.jsx
@@ -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 FileOutlined from '@ant-design/icons-vue/FileOutlined';
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 animation from '../_util/openAnimation';
import PropTypes from '../_util/vue-types';
-import {
- initDefaultProps,
- getOptionProps,
- filterEmpty,
- getComponentFromProp,
- getListeners,
-} from '../_util/props-util';
+import { initDefaultProps, getOptionProps, getComponent, getSlot } from '../_util/props-util';
import { cloneElement } from '../_util/vnode';
import { ConfigConsumerProps } from '../config-provider';
@@ -89,7 +84,6 @@ function TreeProps() {
prefixCls: PropTypes.string,
filterTreeNode: PropTypes.func,
openAnimation: PropTypes.any,
- treeNodes: PropTypes.array,
treeData: PropTypes.array,
/**
* @default{title,key,children}
@@ -104,27 +98,20 @@ export { TreeProps };
export default {
name: 'ATree',
- model: {
- prop: 'checkedKeys',
- event: 'check',
- },
+ inheritAttrs: false,
props: initDefaultProps(TreeProps(), {
checkable: false,
showIcon: false,
openAnimation: {
- on: animation,
- props: { appear: null },
+ ...animation,
+ appear: null,
},
blockNode: false,
}),
- inject: {
- configProvider: { default: () => ConfigConsumerProps },
- },
- created() {
- warning(
- !('treeNodes' in getOptionProps(this)),
- '`treeNodes` is deprecated. please use treeData instead.',
- );
+ setup() {
+ return {
+ configProvider: inject('configProvider', ConfigConsumerProps),
+ };
},
TreeNode,
methods: {
@@ -146,34 +133,32 @@ export default {
});
}
return showLine ? (
- expanded ?
- :
+ expanded ? (
+
+ ) : (
+ )
) : (
);
},
updateTreeData(treeData) {
- const { $slots, $scopedSlots } = this;
+ const { $slots } = this;
const defaultFields = { children: 'children', title: 'title', key: 'key' };
const replaceFields = { ...defaultFields, ...this.$props.replaceFields };
return treeData.map(item => {
const key = item[replaceFields.key];
const children = item[replaceFields.children];
- const { on = {}, slots = {}, scopedSlots = {}, class: cls, style, ...restProps } = item;
+ const { slots = {}, scopedSlots = {}, class: cls, style, ...restProps } = item;
const treeNodeProps = {
...restProps,
- icon: $scopedSlots[scopedSlots.icon] || $slots[slots.icon] || restProps.icon,
+ icon: $slots[scopedSlots.icon] || $slots[slots.icon] || restProps.icon,
switcherIcon:
- $scopedSlots[scopedSlots.switcherIcon] ||
+ $slots[scopedSlots.switcherIcon] ||
$slots[slots.switcherIcon] ||
restProps.switcherIcon,
- title:
- $scopedSlots[scopedSlots.title] ||
- $slots[slots.title] ||
- restProps[replaceFields.title],
+ title: $slots[scopedSlots.title] || $slots[slots.title] || restProps[replaceFields.title],
dataRef: item,
- on,
key,
class: cls,
style,
@@ -184,37 +169,38 @@ export default {
return treeNodeProps;
});
},
+ setTreeRef(node) {
+ this.tree = node;
+ },
},
render() {
const props = getOptionProps(this);
- const { $slots, $scopedSlots } = this;
const { prefixCls: customizePrefixCls, showIcon, treeNodes, blockNode } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
- const switcherIcon = getComponentFromProp(this, 'switcherIcon');
+ const switcherIcon = getComponent(this, 'switcherIcon');
const checkable = props.checkable;
let treeData = props.treeData || treeNodes;
if (treeData) {
treeData = this.updateTreeData(treeData);
}
+ const { class: className, ...restAttrs } = this.$attrs;
const vcTreeProps = {
- props: {
- ...props,
- prefixCls,
- checkable: checkable ? : checkable,
- children: filterEmpty($scopedSlots.default ? $scopedSlots.default() : $slots.default),
- __propsSymbol__: Symbol(),
- switcherIcon: nodeProps => this.renderSwitcherIcon(prefixCls, switcherIcon, nodeProps),
- },
- on: getListeners(this),
- ref: 'tree',
- class: {
+ ...props,
+ prefixCls,
+ checkable: checkable ? : checkable,
+ children: getSlot(this),
+ __propsSymbol__: Symbol(),
+ switcherIcon: nodeProps => this.renderSwitcherIcon(prefixCls, switcherIcon, nodeProps),
+ ref: this.setTreeRef,
+ ...restAttrs,
+ class: classNames(className, {
[`${prefixCls}-icon-hide`]: !showIcon,
[`${prefixCls}-block-node`]: blockNode,
- },
+ }),
};
if (treeData) {
- vcTreeProps.props.treeData = treeData;
+ vcTreeProps.treeData = treeData;
}
return ;
},
diff --git a/components/tree/index.jsx b/components/tree/index.jsx
index c46914ab7..a3c9274df 100644
--- a/components/tree/index.jsx
+++ b/components/tree/index.jsx
@@ -1,15 +1,13 @@
import Tree from './Tree';
import DirectoryTree from './DirectoryTree';
-import Base from '../base';
Tree.TreeNode.name = 'ATreeNode';
Tree.DirectoryTree = DirectoryTree;
/* istanbul ignore next */
-Tree.install = function(Vue) {
- Vue.use(Base);
- Vue.component(Tree.name, Tree);
- Vue.component(Tree.TreeNode.name, Tree.TreeNode);
- Vue.component(DirectoryTree.name, DirectoryTree);
+Tree.install = function(app) {
+ app.component(Tree.name, Tree);
+ app.component(Tree.TreeNode.name, Tree.TreeNode);
+ app.component(DirectoryTree.name, DirectoryTree);
};
export default Tree;
diff --git a/components/tree/util.js b/components/tree/util.js
index 496acd15f..fcba30ba4 100644
--- a/components/tree/util.js
+++ b/components/tree/util.js
@@ -13,7 +13,7 @@ function traverseNodesKey(rootChildren, callback) {
function processNode(node) {
const { key } = node;
- const children = getSlots(node).default;
+ const children = getSlots(node);
if (callback(key, node) !== false) {
traverseNodesKey(typeof children === 'function' ? children() : children, callback);
}
diff --git a/components/vc-tree/src/Tree.jsx b/components/vc-tree/src/Tree.jsx
index 6647e37be..c64ddaac0 100644
--- a/components/vc-tree/src/Tree.jsx
+++ b/components/vc-tree/src/Tree.jsx
@@ -4,7 +4,6 @@ import warning from 'warning';
import { hasProp, initDefaultProps, getOptionProps, getSlots } from '../../_util/props-util';
import { cloneElement } from '../../_util/vnode';
import BaseMixin from '../../_util/BaseMixin';
-import proxyComponent from '../../_util/proxyComponent';
import {
convertTreeToEntities,
convertDataToTree,
@@ -20,6 +19,7 @@ import {
mapChildren,
conductCheck,
warnOnlyTreeNode,
+ getDataAndAria,
} from './util';
/**
@@ -39,6 +39,7 @@ function getWatch(keys = []) {
const Tree = {
name: 'Tree',
+ inheritAttrs: false,
mixins: [BaseMixin],
props: initDefaultProps(
{
@@ -85,7 +86,7 @@ const Tree = {
openTransitionName: PropTypes.string,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
switcherIcon: PropTypes.any,
- _propsSymbol: PropTypes.any,
+ __propsSymbol__: PropTypes.any,
},
{
prefixCls: 'rc-tree',
@@ -169,7 +170,7 @@ const Tree = {
// Check if `treeData` or `children` changed and save into the state.
if (needSync('treeData')) {
- treeNode = convertDataToTree(this.$createElement, props.treeData);
+ treeNode = convertDataToTree(props.treeData);
} else if (needSync('children')) {
treeNode = props.children;
}
@@ -248,7 +249,7 @@ const Tree = {
onNodeDragStart(event, node) {
const { _expandedKeys } = this.$data;
const { eventKey } = node;
- const children = getSlots(node).default;
+ const children = getSlots(node);
this.dragNode = node;
this.setState({
@@ -272,7 +273,7 @@ const Tree = {
const { _expandedKeys: expandedKeys } = this.$data;
const { pos, eventKey } = node;
- if (!this.dragNode || !node.$refs.selectHandle) return;
+ if (!this.dragNode || !node.selectHandle) return;
const dropPosition = calcDropPosition(event, node);
@@ -319,7 +320,7 @@ const Tree = {
const { eventKey } = node;
const { _dragOverNodeKey, _dropPosition } = this.$data;
// Update drag position
- if (this.dragNode && eventKey === _dragOverNodeKey && node.$refs.selectHandle) {
+ if (this.dragNode && eventKey === _dragOverNodeKey && node.selectHandle) {
const dropPosition = calcDropPosition(event, node);
if (dropPosition === _dropPosition) return;
@@ -479,6 +480,7 @@ const Tree = {
_halfCheckedKeys: halfCheckedKeys,
});
}
+ this.$emit('update:checkedKeys', checkedObj);
this.__emit('check', checkedObj, eventObj);
},
onNodeLoad(treeNode) {
@@ -637,21 +639,19 @@ const Tree = {
}
return cloneElement(child, {
- props: {
- eventKey: key,
- expanded: expandedKeys.indexOf(key) !== -1,
- selected: selectedKeys.indexOf(key) !== -1,
- loaded: loadedKeys.indexOf(key) !== -1,
- loading: loadingKeys.indexOf(key) !== -1,
- checked: this.isKeyChecked(key),
- halfChecked: halfCheckedKeys.indexOf(key) !== -1,
- pos,
+ eventKey: key,
+ expanded: expandedKeys.indexOf(key) !== -1,
+ selected: selectedKeys.indexOf(key) !== -1,
+ loaded: loadedKeys.indexOf(key) !== -1,
+ loading: loadingKeys.indexOf(key) !== -1,
+ checked: this.isKeyChecked(key),
+ halfChecked: halfCheckedKeys.indexOf(key) !== -1,
+ pos,
- // [Legacy] Drag props
- dragOver: dragOverNodeKey === key && dropPosition === 0,
- dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
- dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1,
- },
+ // [Legacy] Drag props
+ dragOver: dragOverNodeKey === key && dropPosition === 0,
+ dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
+ dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1,
key,
});
},
@@ -660,12 +660,15 @@ const Tree = {
render() {
const { _treeNode: treeNode } = this.$data;
const { prefixCls, focusable, showLine, tabIndex = 0 } = this.$props;
-
+ const domProps = getDataAndAria({ ...this.$props, ...this.$attrs });
+ const { class: className, style } = this.$attrs;
return (
({}) },
vcTreeNode: { default: () => ({}) },
},
- provide() {
- return {
- vcTreeNode: this,
- };
+ created() {
+ provide('vcTreeNode', this);
},
-
// Isomorphic needn't load data in server side
mounted() {
const {
@@ -234,6 +239,10 @@ const TreeNode = {
} = this;
onNodeExpand(e, this);
},
+ // Drag usage
+ setSelectHandle(node) {
+ this.selectHandle = node;
+ },
getNodeChildren() {
const {
@@ -336,8 +345,8 @@ const TreeNode = {
vcTree: { prefixCls },
} = this;
const switcherIcon =
- getComponentFromProp(this, 'switcherIcon', {}, false) ||
- getComponentFromProp(this.vcTree, 'switcherIcon', {}, false);
+ getComponent(this, 'switcherIcon', {}, false) ||
+ getComponent(this.vcTree, 'switcherIcon', {}, false);
if (this.isLeaf2()) {
return (
{typeof currentIcon === 'function'
- ? currentIcon({ ...this.$props, ...this.$props.dataRef }, h)
+ ? currentIcon({ ...this.$props, ...this.$props.dataRef })
: currentIcon}
) : (
@@ -445,17 +454,16 @@ const TreeNode = {
let $title = currentTitle ? (
{typeof currentTitle === 'function'
- ? currentTitle({ ...this.$props, ...this.$props.dataRef }, h)
+ ? currentTitle({ ...this.$props, ...this.$props.dataRef })
: currentTitle}
) : (
{defaultTitle}
);
-
return (
{this.renderSwitcher()}
{this.renderCheckbox()}
- {this.renderSelector(h)}
+ {this.renderSelector()}
{this.renderChildren()}
);
diff --git a/components/vc-tree/src/util.js b/components/vc-tree/src/util.js
index cf5cfc1d4..5ee8dd1e9 100644
--- a/components/vc-tree/src/util.js
+++ b/components/vc-tree/src/util.js
@@ -1,8 +1,7 @@
/* eslint no-loop-func: 0*/
import warning from 'warning';
-import omit from 'omit.js';
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_MIN_GAP = 2;
@@ -41,7 +40,7 @@ export function getPosition(level, index) {
}
export function isTreeNode(node) {
- return getSlotOptions(node).isTreeNode;
+ return typeof node.type === 'object' && node.type.isTreeNode;
}
export function getNodeChildren(children = []) {
@@ -55,7 +54,7 @@ export function isCheckDisabled(node) {
export function traverseTreeNodes(treeNodes, callback) {
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;
// Filter children
@@ -111,7 +110,7 @@ export function getDragNodesKeys(treeNodes, node) {
export function calcDropPosition(event, treeNode) {
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);
if (clientY <= top + des) {
@@ -156,20 +155,19 @@ export function calcSelectedKeys(selectedKeys, props) {
const internalProcessProps = (props = {}) => {
return {
- props: omit(props, ['on', 'key', 'class', 'className', 'style']),
- on: props.on || {},
+ ...props,
class: props.class || props.className,
style: props.style,
key: props.key,
};
};
-export function convertDataToTree(h, treeData, processor) {
+export function convertDataToTree(treeData, processor) {
if (!treeData) return [];
const { processProps = internalProcessProps } = processor || {};
const list = Array.isArray(treeData) ? treeData : [treeData];
return list.map(({ children, ...props }) => {
- const childrenNodes = convertDataToTree(h, children, processor);
+ const childrenNodes = convertDataToTree(children, processor);
return {childrenNodes};
});
}
diff --git a/examples/App.vue b/examples/App.vue
index 22a8dc78f..23d1d7dac 100644
--- a/examples/App.vue
+++ b/examples/App.vue
@@ -4,7 +4,7 @@