perf: tree, close #5551
parent
53b4c5d8b2
commit
9aeadaf877
|
@ -16,8 +16,8 @@ import PropTypes from '../_util/vue-types';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import devWarning from '../vc-util/devWarning';
|
import devWarning from '../vc-util/devWarning';
|
||||||
import getIcons from '../select/utils/iconUtil';
|
import getIcons from '../select/utils/iconUtil';
|
||||||
|
import type { SwitcherIconProps } from '../tree/utils/iconUtil';
|
||||||
import renderSwitcherIcon from '../tree/utils/iconUtil';
|
import renderSwitcherIcon from '../tree/utils/iconUtil';
|
||||||
import type { AntTreeNodeProps } from '../tree/Tree';
|
|
||||||
import { warning } from '../vc-util/warning';
|
import { warning } from '../vc-util/warning';
|
||||||
import { flattenChildren } from '../_util/props-util';
|
import { flattenChildren } from '../_util/props-util';
|
||||||
import { useInjectFormItemContext } from '../form/FormItemContext';
|
import { useInjectFormItemContext } from '../form/FormItemContext';
|
||||||
|
@ -239,7 +239,7 @@ const TreeSelect = defineComponent({
|
||||||
multiple={multiple}
|
multiple={multiple}
|
||||||
removeIcon={removeIcon}
|
removeIcon={removeIcon}
|
||||||
clearIcon={clearIcon}
|
clearIcon={clearIcon}
|
||||||
switcherIcon={(nodeProps: AntTreeNodeProps) =>
|
switcherIcon={(nodeProps: SwitcherIconProps) =>
|
||||||
renderSwitcherIcon(treePrefixCls.value, switcherIcon, treeLine, nodeProps)
|
renderSwitcherIcon(treePrefixCls.value, switcherIcon, treeLine, nodeProps)
|
||||||
}
|
}
|
||||||
showTreeIcon={treeIcon as any}
|
showTreeIcon={treeIcon as any}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import type { DataNode, EventDataNode, FieldNames, Key } from '../vc-tree/interf
|
||||||
import type { TreeNodeProps } from '../vc-tree/props';
|
import type { TreeNodeProps } from '../vc-tree/props';
|
||||||
import { treeProps as vcTreeProps } from '../vc-tree/props';
|
import { treeProps as vcTreeProps } from '../vc-tree/props';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import type { SwitcherIconProps } from './utils/iconUtil';
|
||||||
import renderSwitcherIcon from './utils/iconUtil';
|
import renderSwitcherIcon from './utils/iconUtil';
|
||||||
import dropIndicatorRender from './utils/dropIndicator';
|
import dropIndicatorRender from './utils/dropIndicator';
|
||||||
import devWarning from '../vc-util/devWarning';
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
@ -229,7 +230,7 @@ export default defineComponent({
|
||||||
icon,
|
icon,
|
||||||
itemHeight,
|
itemHeight,
|
||||||
};
|
};
|
||||||
|
const children = slots.default ? filterEmpty(slots.default()) : undefined;
|
||||||
return (
|
return (
|
||||||
<VcTree
|
<VcTree
|
||||||
{...newProps}
|
{...newProps}
|
||||||
|
@ -249,7 +250,7 @@ export default defineComponent({
|
||||||
direction={direction.value}
|
direction={direction.value}
|
||||||
checkable={checkable}
|
checkable={checkable}
|
||||||
selectable={selectable}
|
selectable={selectable}
|
||||||
switcherIcon={(nodeProps: AntTreeNodeProps) =>
|
switcherIcon={(nodeProps: SwitcherIconProps) =>
|
||||||
renderSwitcherIcon(prefixCls.value, switcherIcon, showLine, nodeProps)
|
renderSwitcherIcon(prefixCls.value, switcherIcon, showLine, nodeProps)
|
||||||
}
|
}
|
||||||
onCheck={handleCheck}
|
onCheck={handleCheck}
|
||||||
|
@ -260,7 +261,7 @@ export default defineComponent({
|
||||||
...slots,
|
...slots,
|
||||||
checkable: () => <span class={`${prefixCls.value}-checkbox-inner`} />,
|
checkable: () => <span class={`${prefixCls.value}-checkbox-inner`} />,
|
||||||
}}
|
}}
|
||||||
children={filterEmpty(slots.default?.())}
|
children={children}
|
||||||
></VcTree>
|
></VcTree>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,12 +7,15 @@ import type { AntTreeNodeProps } from '../Tree';
|
||||||
import { isValidElement } from '../../_util/props-util';
|
import { isValidElement } from '../../_util/props-util';
|
||||||
|
|
||||||
import { cloneVNode } from 'vue';
|
import { cloneVNode } from 'vue';
|
||||||
|
export interface SwitcherIconProps extends AntTreeNodeProps {
|
||||||
|
expanded: boolean;
|
||||||
|
loading: boolean;
|
||||||
|
}
|
||||||
export default function renderSwitcherIcon(
|
export default function renderSwitcherIcon(
|
||||||
prefixCls: string,
|
prefixCls: string,
|
||||||
switcherIcon: any,
|
switcherIcon: any,
|
||||||
showLine: boolean | { showLeafIcon: boolean } | undefined,
|
showLine: boolean | { showLeafIcon: boolean } | undefined,
|
||||||
props: AntTreeNodeProps,
|
props: SwitcherIconProps,
|
||||||
) {
|
) {
|
||||||
const { isLeaf, expanded, loading } = props;
|
const { isLeaf, expanded, loading } = props;
|
||||||
let icon = switcherIcon;
|
let icon = switcherIcon;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import TreeNode from './TreeNode';
|
import TreeNode from './TreeNode';
|
||||||
import type { FlattenNode } from './interface';
|
import type { FlattenNode } from './interface';
|
||||||
import type { TreeNodeRequiredProps } from './utils/treeUtil';
|
|
||||||
import { getTreeNodeProps } from './utils/treeUtil';
|
|
||||||
import { useInjectTreeContext } from './contextTypes';
|
import { useInjectTreeContext } from './contextTypes';
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import {
|
import {
|
||||||
|
@ -28,7 +26,7 @@ export default defineComponent({
|
||||||
onMotionStart: Function,
|
onMotionStart: Function,
|
||||||
onMotionEnd: Function,
|
onMotionEnd: Function,
|
||||||
motionType: String,
|
motionType: String,
|
||||||
treeNodeRequiredProps: { type: Object as PropType<TreeNodeRequiredProps> },
|
// treeNodeRequiredProps: { type: Object as PropType<TreeNodeRequiredProps> },
|
||||||
},
|
},
|
||||||
slots: ['title', 'icon', 'switcherIcon', 'checkable'],
|
slots: ['title', 'icon', 'switcherIcon', 'checkable'],
|
||||||
setup(props, { attrs, slots }) {
|
setup(props, { attrs, slots }) {
|
||||||
|
@ -73,8 +71,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const { motion, motionNodes, motionType, active, treeNodeRequiredProps, ...otherProps } =
|
const { motion, motionNodes, motionType, active, eventKey, ...otherProps } = props;
|
||||||
props;
|
|
||||||
if (motionNodes) {
|
if (motionNodes) {
|
||||||
return (
|
return (
|
||||||
<Transition
|
<Transition
|
||||||
|
@ -94,17 +91,15 @@ export default defineComponent({
|
||||||
} = treeNode;
|
} = treeNode;
|
||||||
delete restProps.children;
|
delete restProps.children;
|
||||||
|
|
||||||
const treeNodeProps = getTreeNodeProps(key, treeNodeRequiredProps);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
v-slots={slots}
|
v-slots={slots}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
{...treeNodeProps}
|
|
||||||
title={title}
|
title={title}
|
||||||
active={active}
|
active={active}
|
||||||
data={treeNode.data}
|
data={treeNode.data}
|
||||||
key={key}
|
key={key}
|
||||||
|
eventKey={key}
|
||||||
isStart={isStart}
|
isStart={isStart}
|
||||||
isEnd={isEnd}
|
isEnd={isEnd}
|
||||||
/>
|
/>
|
||||||
|
@ -122,6 +117,7 @@ export default defineComponent({
|
||||||
style={attrs.style}
|
style={attrs.style}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
active={active}
|
active={active}
|
||||||
|
eventKey={eventKey}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
|
|
||||||
import { computed, defineComponent, ref, shallowRef, watch } from 'vue';
|
import { computed, defineComponent, ref, shallowRef, watch } from 'vue';
|
||||||
import VirtualList from '../vc-virtual-list';
|
import VirtualList from '../vc-virtual-list';
|
||||||
|
import omit from '../_util/omit';
|
||||||
|
import { useInjectKeysState, useInjectTreeContext } from './contextTypes';
|
||||||
import type { FlattenNode, DataEntity, DataNode, ScrollTo } from './interface';
|
import type { FlattenNode, DataEntity, DataNode, ScrollTo } from './interface';
|
||||||
import MotionTreeNode from './MotionTreeNode';
|
import MotionTreeNode from './MotionTreeNode';
|
||||||
import type { NodeListProps } from './props';
|
import type { NodeListProps } from './props';
|
||||||
import { nodeListProps } from './props';
|
import { nodeListProps } from './props';
|
||||||
import { findExpandedKeys, getExpandRange } from './utils/diffUtil';
|
import { findExpandedKeys, getExpandRange } from './utils/diffUtil';
|
||||||
import { getTreeNodeProps, getKey } from './utils/treeUtil';
|
import { getKey } from './utils/treeUtil';
|
||||||
|
|
||||||
const HIDDEN_STYLE = {
|
const HIDDEN_STYLE = {
|
||||||
width: 0,
|
width: 0,
|
||||||
|
@ -97,6 +99,7 @@ export default defineComponent({
|
||||||
// =============================== Ref ================================
|
// =============================== Ref ================================
|
||||||
const listRef = ref();
|
const listRef = ref();
|
||||||
const indentMeasurerRef = ref();
|
const indentMeasurerRef = ref();
|
||||||
|
const { expandedKeys, flattenNodes } = useInjectKeysState();
|
||||||
expose({
|
expose({
|
||||||
scrollTo: scroll => {
|
scrollTo: scroll => {
|
||||||
listRef.value.scrollTo(scroll);
|
listRef.value.scrollTo(scroll);
|
||||||
|
@ -104,19 +107,21 @@ export default defineComponent({
|
||||||
getIndentWidth: () => indentMeasurerRef.value.offsetWidth,
|
getIndentWidth: () => indentMeasurerRef.value.offsetWidth,
|
||||||
});
|
});
|
||||||
// ============================== Motion ==============================
|
// ============================== Motion ==============================
|
||||||
const transitionData = shallowRef<FlattenNode[]>(props.data);
|
const transitionData = shallowRef<FlattenNode[]>(flattenNodes.value);
|
||||||
const transitionRange = shallowRef([]);
|
const transitionRange = shallowRef([]);
|
||||||
const motionType = ref<'show' | 'hide' | null>(null);
|
const motionType = ref<'show' | 'hide' | null>(null);
|
||||||
|
|
||||||
function onMotionEnd() {
|
function onMotionEnd() {
|
||||||
transitionData.value = props.data;
|
transitionData.value = flattenNodes.value;
|
||||||
transitionRange.value = [];
|
transitionRange.value = [];
|
||||||
motionType.value = null;
|
motionType.value = null;
|
||||||
|
|
||||||
props.onListChangeEnd();
|
props.onListChangeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const context = useInjectTreeContext();
|
||||||
watch(
|
watch(
|
||||||
[() => [...props.expandedKeys], () => props.data],
|
[() => expandedKeys.value.slice(), flattenNodes],
|
||||||
([expandedKeys, data], [prevExpandedKeys, prevData]) => {
|
([expandedKeys, data], [prevExpandedKeys, prevData]) => {
|
||||||
const diffExpanded = findExpandedKeys(prevExpandedKeys, expandedKeys);
|
const diffExpanded = findExpandedKeys(prevExpandedKeys, expandedKeys);
|
||||||
if (diffExpanded.key !== null) {
|
if (diffExpanded.key !== null) {
|
||||||
|
@ -160,7 +165,7 @@ export default defineComponent({
|
||||||
);
|
);
|
||||||
// We should clean up motion if is changed by dragging
|
// We should clean up motion if is changed by dragging
|
||||||
watch(
|
watch(
|
||||||
() => props.dragging,
|
() => context.value.dragging,
|
||||||
dragging => {
|
dragging => {
|
||||||
if (!dragging) {
|
if (!dragging) {
|
||||||
onMotionEnd();
|
onMotionEnd();
|
||||||
|
@ -169,27 +174,18 @@ export default defineComponent({
|
||||||
);
|
);
|
||||||
|
|
||||||
const mergedData = computed(() =>
|
const mergedData = computed(() =>
|
||||||
props.motion === undefined ? transitionData.value : props.data,
|
props.motion === undefined ? transitionData.value : flattenNodes.value,
|
||||||
);
|
);
|
||||||
|
const onActiveChange = () => {
|
||||||
|
props.onActiveChange(null);
|
||||||
|
};
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
data,
|
|
||||||
selectable,
|
selectable,
|
||||||
checkable,
|
checkable,
|
||||||
expandedKeys,
|
|
||||||
selectedKeys,
|
|
||||||
checkedKeys,
|
|
||||||
loadedKeys,
|
|
||||||
loadingKeys,
|
|
||||||
halfCheckedKeys,
|
|
||||||
keyEntities,
|
|
||||||
disabled,
|
disabled,
|
||||||
|
|
||||||
dragging,
|
|
||||||
dragOverNodeKey,
|
|
||||||
dropPosition,
|
|
||||||
motion,
|
motion,
|
||||||
|
|
||||||
height,
|
height,
|
||||||
|
@ -204,25 +200,12 @@ export default defineComponent({
|
||||||
onKeydown,
|
onKeydown,
|
||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
onActiveChange,
|
|
||||||
|
|
||||||
onListChangeStart,
|
onListChangeStart,
|
||||||
onListChangeEnd,
|
onListChangeEnd,
|
||||||
|
|
||||||
...domProps
|
...domProps
|
||||||
} = { ...props, ...attrs } as NodeListProps;
|
} = { ...props, ...attrs } as NodeListProps;
|
||||||
|
|
||||||
const treeNodeRequiredProps = {
|
|
||||||
expandedKeys,
|
|
||||||
selectedKeys,
|
|
||||||
loadedKeys,
|
|
||||||
loadingKeys,
|
|
||||||
checkedKeys,
|
|
||||||
halfCheckedKeys,
|
|
||||||
dragOverNodeKey,
|
|
||||||
dropPosition,
|
|
||||||
keyEntities,
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{focused && activeItem && (
|
{focused && activeItem && (
|
||||||
|
@ -262,7 +245,7 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<VirtualList
|
<VirtualList
|
||||||
{...domProps}
|
{...omit(domProps, ['onActiveChange'])}
|
||||||
data={mergedData.value}
|
data={mergedData.value}
|
||||||
itemKey={itemKey as any}
|
itemKey={itemKey as any}
|
||||||
height={height}
|
height={height}
|
||||||
|
@ -293,15 +276,12 @@ export default defineComponent({
|
||||||
const mergedKey = getKey(key, pos);
|
const mergedKey = getKey(key, pos);
|
||||||
delete restProps.key;
|
delete restProps.key;
|
||||||
delete restProps.children;
|
delete restProps.children;
|
||||||
|
|
||||||
const treeNodeProps = getTreeNodeProps(mergedKey, treeNodeRequiredProps);
|
|
||||||
return (
|
return (
|
||||||
<MotionTreeNode
|
<MotionTreeNode
|
||||||
{...restProps}
|
{...restProps}
|
||||||
{...treeNodeProps}
|
eventKey={mergedKey}
|
||||||
title={title}
|
title={title}
|
||||||
active={!!activeItem && key === activeItem.key}
|
active={!!activeItem && key === activeItem.key}
|
||||||
pos={pos}
|
|
||||||
data={treeNode.data}
|
data={treeNode.data}
|
||||||
isStart={isStart}
|
isStart={isStart}
|
||||||
isEnd={isEnd}
|
isEnd={isEnd}
|
||||||
|
@ -310,10 +290,7 @@ export default defineComponent({
|
||||||
motionType={motionType.value}
|
motionType={motionType.value}
|
||||||
onMotionStart={onListChangeStart}
|
onMotionStart={onListChangeStart}
|
||||||
onMotionEnd={onMotionEnd}
|
onMotionEnd={onMotionEnd}
|
||||||
treeNodeRequiredProps={treeNodeRequiredProps}
|
onMousemove={onActiveChange}
|
||||||
onMousemove={() => {
|
|
||||||
onActiveChange(null);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { NodeMouseEventHandler, NodeDragEventHandler } from './contextTypes';
|
import type { NodeMouseEventHandler, NodeDragEventHandler } from './contextTypes';
|
||||||
import { TreeContext } from './contextTypes';
|
import { useProvideKeysState, TreeContext } from './contextTypes';
|
||||||
import {
|
import {
|
||||||
getDragChildrenKeys,
|
getDragChildrenKeys,
|
||||||
parseCheckedKeys,
|
parseCheckedKeys,
|
||||||
|
@ -11,6 +11,7 @@ import {
|
||||||
posToArr,
|
posToArr,
|
||||||
} from './util';
|
} from './util';
|
||||||
import type { Key, FlattenNode, EventDataNode, ScrollTo, DragNodeEvent } from './interface';
|
import type { Key, FlattenNode, EventDataNode, ScrollTo, DragNodeEvent } from './interface';
|
||||||
|
import type { TreeNodeRequiredProps } from './utils/treeUtil';
|
||||||
import {
|
import {
|
||||||
flattenTreeData,
|
flattenTreeData,
|
||||||
convertTreeToData,
|
convertTreeToData,
|
||||||
|
@ -78,12 +79,12 @@ export default defineComponent({
|
||||||
const destroyed = ref(false);
|
const destroyed = ref(false);
|
||||||
let delayedDragEnterLogic: Record<Key, number> = {};
|
let delayedDragEnterLogic: Record<Key, number> = {};
|
||||||
const indent = ref();
|
const indent = ref();
|
||||||
const selectedKeys = shallowRef([]);
|
const selectedKeys = shallowRef<Key[]>([]);
|
||||||
const checkedKeys = shallowRef([]);
|
const checkedKeys = shallowRef<Key[]>([]);
|
||||||
const halfCheckedKeys = shallowRef([]);
|
const halfCheckedKeys = shallowRef<Key[]>([]);
|
||||||
const loadedKeys = shallowRef([]);
|
const loadedKeys = shallowRef<Key[]>([]);
|
||||||
const loadingKeys = shallowRef([]);
|
const loadingKeys = shallowRef<Key[]>([]);
|
||||||
const expandedKeys = shallowRef([]);
|
const expandedKeys = shallowRef<Key[]>([]);
|
||||||
const loadingRetryTimes: Record<Key, number> = {};
|
const loadingRetryTimes: Record<Key, number> = {};
|
||||||
const dragState = reactive({
|
const dragState = reactive({
|
||||||
draggingNodeKey: null,
|
draggingNodeKey: null,
|
||||||
|
@ -112,7 +113,10 @@ export default defineComponent({
|
||||||
? toRaw(props.treeData).slice()
|
? toRaw(props.treeData).slice()
|
||||||
: convertTreeToData(toRaw(props.children));
|
: convertTreeToData(toRaw(props.children));
|
||||||
},
|
},
|
||||||
{ immediate: true, deep: true },
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const keyEntities = shallowRef({});
|
const keyEntities = shallowRef({});
|
||||||
|
|
||||||
|
@ -131,19 +135,37 @@ export default defineComponent({
|
||||||
|
|
||||||
let currentMouseOverDroppableNodeKey = null;
|
let currentMouseOverDroppableNodeKey = null;
|
||||||
|
|
||||||
const treeNodeRequiredProps = computed(() => {
|
const treeNodeRequiredProps = computed<TreeNodeRequiredProps>(() => {
|
||||||
return {
|
return {
|
||||||
expandedKeys: expandedKeys.value || [],
|
expandedKeysSet: expandedKeysSet.value,
|
||||||
selectedKeys: selectedKeys.value || [],
|
selectedKeysSet: selectedKeysSet.value,
|
||||||
loadedKeys: loadedKeys.value || [],
|
loadedKeysSet: loadedKeysSet.value,
|
||||||
loadingKeys: loadingKeys.value || [],
|
loadingKeysSet: loadingKeysSet.value,
|
||||||
checkedKeys: checkedKeys.value || [],
|
checkedKeysSet: checkedKeysSet.value,
|
||||||
halfCheckedKeys: halfCheckedKeys.value || [],
|
halfCheckedKeysSet: halfCheckedKeysSet.value,
|
||||||
dragOverNodeKey: dragState.dragOverNodeKey,
|
dragOverNodeKey: dragState.dragOverNodeKey,
|
||||||
dropPosition: dragState.dropPosition,
|
dropPosition: dragState.dropPosition,
|
||||||
keyEntities: keyEntities.value,
|
keyEntities: keyEntities.value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const expandedKeysSet = computed(() => {
|
||||||
|
return new Set(expandedKeys.value);
|
||||||
|
});
|
||||||
|
const selectedKeysSet = computed(() => {
|
||||||
|
return new Set(selectedKeys.value);
|
||||||
|
});
|
||||||
|
const loadedKeysSet = computed(() => {
|
||||||
|
return new Set(loadedKeys.value);
|
||||||
|
});
|
||||||
|
const loadingKeysSet = computed(() => {
|
||||||
|
return new Set(loadingKeys.value);
|
||||||
|
});
|
||||||
|
const checkedKeysSet = computed(() => {
|
||||||
|
return new Set(checkedKeys.value);
|
||||||
|
});
|
||||||
|
const halfCheckedKeysSet = computed(() => {
|
||||||
|
return new Set(halfCheckedKeys.value);
|
||||||
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (treeData.value) {
|
if (treeData.value) {
|
||||||
|
@ -388,7 +410,7 @@ export default defineComponent({
|
||||||
allowDrop,
|
allowDrop,
|
||||||
flattenNodes.value,
|
flattenNodes.value,
|
||||||
keyEntities.value,
|
keyEntities.value,
|
||||||
expandedKeys.value,
|
expandedKeysSet.value,
|
||||||
direction,
|
direction,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -485,7 +507,7 @@ export default defineComponent({
|
||||||
allowDrop,
|
allowDrop,
|
||||||
flattenNodes.value,
|
flattenNodes.value,
|
||||||
keyEntities.value,
|
keyEntities.value,
|
||||||
expandedKeys.value,
|
expandedKeysSet.value,
|
||||||
direction,
|
direction,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -558,7 +580,6 @@ export default defineComponent({
|
||||||
const onNodeDrop = (event: DragEvent, _node, outsideTree = false) => {
|
const onNodeDrop = (event: DragEvent, _node, outsideTree = false) => {
|
||||||
const { dragChildrenKeys, dropPosition, dropTargetKey, dropTargetPos, dropAllowed } =
|
const { dragChildrenKeys, dropPosition, dropTargetKey, dropTargetPos, dropAllowed } =
|
||||||
dragState;
|
dragState;
|
||||||
|
|
||||||
if (!dropAllowed) return;
|
if (!dropAllowed) return;
|
||||||
|
|
||||||
const { onDrop } = props;
|
const { onDrop } = props;
|
||||||
|
@ -735,11 +756,7 @@ export default defineComponent({
|
||||||
// We need to get the latest state of loading/loaded keys
|
// We need to get the latest state of loading/loaded keys
|
||||||
const { loadData, onLoad } = props;
|
const { loadData, onLoad } = props;
|
||||||
|
|
||||||
if (
|
if (!loadData || loadedKeysSet.value.has(key) || loadingKeysSet.value.has(key)) {
|
||||||
!loadData ||
|
|
||||||
loadedKeys.value.indexOf(key) !== -1 ||
|
|
||||||
loadingKeys.value.indexOf(key) !== -1
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,7 +994,7 @@ export default defineComponent({
|
||||||
// >>> Expand
|
// >>> Expand
|
||||||
case KeyCode.LEFT: {
|
case KeyCode.LEFT: {
|
||||||
// Collapse if possible
|
// Collapse if possible
|
||||||
if (expandable && expandedKeys.value.includes(activeKey.value)) {
|
if (expandable && expandedKeysSet.value.has(activeKey.value)) {
|
||||||
onNodeExpand({} as MouseEvent, eventNode);
|
onNodeExpand({} as MouseEvent, eventNode);
|
||||||
} else if (item.parent) {
|
} else if (item.parent) {
|
||||||
onActiveChange(item.parent.key);
|
onActiveChange(item.parent.key);
|
||||||
|
@ -987,7 +1004,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
case KeyCode.RIGHT: {
|
case KeyCode.RIGHT: {
|
||||||
// Expand if possible
|
// Expand if possible
|
||||||
if (expandable && !expandedKeys.value.includes(activeKey.value)) {
|
if (expandable && !expandedKeysSet.value.has(activeKey.value)) {
|
||||||
onNodeExpand({} as MouseEvent, eventNode);
|
onNodeExpand({} as MouseEvent, eventNode);
|
||||||
} else if (item.children && item.children.length) {
|
} else if (item.children && item.children.length) {
|
||||||
onActiveChange(item.children[0].key);
|
onActiveChange(item.children[0].key);
|
||||||
|
@ -1005,11 +1022,7 @@ export default defineComponent({
|
||||||
eventNode.checkable !== false &&
|
eventNode.checkable !== false &&
|
||||||
!eventNode.disableCheckbox
|
!eventNode.disableCheckbox
|
||||||
) {
|
) {
|
||||||
onNodeCheck(
|
onNodeCheck({} as MouseEvent, eventNode, !checkedKeysSet.value.has(activeKey.value));
|
||||||
{} as MouseEvent,
|
|
||||||
eventNode,
|
|
||||||
!checkedKeys.value.includes(activeKey.value),
|
|
||||||
);
|
|
||||||
} else if (
|
} else if (
|
||||||
!checkable &&
|
!checkable &&
|
||||||
selectable &&
|
selectable &&
|
||||||
|
@ -1042,6 +1055,21 @@ export default defineComponent({
|
||||||
window.removeEventListener('dragend', onWindowDragEnd);
|
window.removeEventListener('dragend', onWindowDragEnd);
|
||||||
destroyed.value = true;
|
destroyed.value = true;
|
||||||
});
|
});
|
||||||
|
useProvideKeysState({
|
||||||
|
expandedKeys,
|
||||||
|
selectedKeys,
|
||||||
|
loadedKeys,
|
||||||
|
loadingKeys,
|
||||||
|
checkedKeys,
|
||||||
|
halfCheckedKeys,
|
||||||
|
expandedKeysSet,
|
||||||
|
selectedKeysSet,
|
||||||
|
loadedKeysSet,
|
||||||
|
loadingKeysSet,
|
||||||
|
checkedKeysSet,
|
||||||
|
halfCheckedKeysSet,
|
||||||
|
flattenNodes,
|
||||||
|
});
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
// focused,
|
// focused,
|
||||||
|
@ -1123,6 +1151,7 @@ export default defineComponent({
|
||||||
dropTargetKey,
|
dropTargetKey,
|
||||||
dropPosition,
|
dropPosition,
|
||||||
dragOverNodeKey,
|
dragOverNodeKey,
|
||||||
|
dragging: draggingNodeKey !== null,
|
||||||
indent: indent.value,
|
indent: indent.value,
|
||||||
direction,
|
direction,
|
||||||
dropIndicatorRender,
|
dropIndicatorRender,
|
||||||
|
@ -1160,12 +1189,10 @@ export default defineComponent({
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
prefixCls={prefixCls}
|
prefixCls={prefixCls}
|
||||||
style={style}
|
style={style}
|
||||||
data={flattenNodes.value}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
selectable={selectable}
|
selectable={selectable}
|
||||||
checkable={!!checkable}
|
checkable={!!checkable}
|
||||||
motion={motion}
|
motion={motion}
|
||||||
dragging={draggingNodeKey !== null}
|
|
||||||
height={height}
|
height={height}
|
||||||
itemHeight={itemHeight}
|
itemHeight={itemHeight}
|
||||||
virtual={virtual}
|
virtual={virtual}
|
||||||
|
@ -1181,7 +1208,6 @@ export default defineComponent({
|
||||||
onListChangeEnd={onListChangeEnd}
|
onListChangeEnd={onListChangeEnd}
|
||||||
onContextmenu={onContextmenu}
|
onContextmenu={onContextmenu}
|
||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
{...treeNodeRequiredProps.value}
|
|
||||||
{...domProps}
|
{...domProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useInjectTreeContext } from './contextTypes';
|
import { useInjectKeysState, useInjectTreeContext } from './contextTypes';
|
||||||
import Indent from './Indent';
|
import Indent from './Indent';
|
||||||
import { convertNodePropsToEventData } from './utils/treeUtil';
|
import { convertNodePropsToEventData, getTreeNodeProps } from './utils/treeUtil';
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
@ -14,8 +14,8 @@ import { treeNodeProps } from './props';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { warning } from '../vc-util/warning';
|
import { warning } from '../vc-util/warning';
|
||||||
import type { DragNodeEvent, Key } from './interface';
|
import type { DragNodeEvent, Key } from './interface';
|
||||||
import pick from 'lodash-es/pick';
|
|
||||||
import pickAttrs from '../_util/pickAttrs';
|
import pickAttrs from '../_util/pickAttrs';
|
||||||
|
import eagerComputed from '../_util/eagerComputed';
|
||||||
|
|
||||||
const ICON_OPEN = 'open';
|
const ICON_OPEN = 'open';
|
||||||
const ICON_CLOSE = 'close';
|
const ICON_CLOSE = 'close';
|
||||||
|
@ -35,8 +35,43 @@ export default defineComponent({
|
||||||
key => '`v-slot:' + key + '` ',
|
key => '`v-slot:' + key + '` ',
|
||||||
)}instead`,
|
)}instead`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const dragNodeHighlight = ref(false);
|
const dragNodeHighlight = ref(false);
|
||||||
const context = useInjectTreeContext();
|
const context = useInjectTreeContext();
|
||||||
|
const {
|
||||||
|
expandedKeysSet,
|
||||||
|
selectedKeysSet,
|
||||||
|
loadedKeysSet,
|
||||||
|
loadingKeysSet,
|
||||||
|
checkedKeysSet,
|
||||||
|
halfCheckedKeysSet,
|
||||||
|
} = useInjectKeysState();
|
||||||
|
const { dragOverNodeKey, dropPosition, keyEntities } = context.value;
|
||||||
|
const mergedTreeNodeProps = computed(() => {
|
||||||
|
return getTreeNodeProps(props.eventKey, {
|
||||||
|
expandedKeysSet: expandedKeysSet.value,
|
||||||
|
selectedKeysSet: selectedKeysSet.value,
|
||||||
|
loadedKeysSet: loadedKeysSet.value,
|
||||||
|
loadingKeysSet: loadingKeysSet.value,
|
||||||
|
checkedKeysSet: checkedKeysSet.value,
|
||||||
|
halfCheckedKeysSet: halfCheckedKeysSet.value,
|
||||||
|
dragOverNodeKey,
|
||||||
|
dropPosition,
|
||||||
|
keyEntities,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const expanded = eagerComputed(() => mergedTreeNodeProps.value.expanded);
|
||||||
|
const selected = eagerComputed(() => mergedTreeNodeProps.value.selected);
|
||||||
|
const checked = eagerComputed(() => mergedTreeNodeProps.value.checked);
|
||||||
|
const loaded = eagerComputed(() => mergedTreeNodeProps.value.loaded);
|
||||||
|
const loading = eagerComputed(() => mergedTreeNodeProps.value.loading);
|
||||||
|
const halfChecked = eagerComputed(() => mergedTreeNodeProps.value.halfChecked);
|
||||||
|
const dragOver = eagerComputed(() => mergedTreeNodeProps.value.dragOver);
|
||||||
|
const dragOverGapTop = eagerComputed(() => mergedTreeNodeProps.value.dragOverGapTop);
|
||||||
|
const dragOverGapBottom = eagerComputed(() => mergedTreeNodeProps.value.dragOverGapBottom);
|
||||||
|
const pos = eagerComputed(() => mergedTreeNodeProps.value.pos);
|
||||||
|
|
||||||
const selectHandle = ref();
|
const selectHandle = ref();
|
||||||
|
|
||||||
const hasChildren = computed(() => {
|
const hasChildren = computed(() => {
|
||||||
|
@ -48,7 +83,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
const isLeaf = computed(() => {
|
const isLeaf = computed(() => {
|
||||||
const { isLeaf, loaded } = props;
|
const { isLeaf } = props;
|
||||||
const { loadData } = context.value;
|
const { loadData } = context.value;
|
||||||
|
|
||||||
const has = hasChildren.value;
|
const has = hasChildren.value;
|
||||||
|
@ -57,16 +92,14 @@ export default defineComponent({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isLeaf || (!loadData && !has) || (loadData && loaded && !has);
|
return isLeaf || (!loadData && !has) || (loadData && loaded.value && !has);
|
||||||
});
|
});
|
||||||
const nodeState = computed(() => {
|
const nodeState = computed(() => {
|
||||||
const { expanded } = props;
|
|
||||||
|
|
||||||
if (isLeaf.value) {
|
if (isLeaf.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return expanded ? ICON_OPEN : ICON_CLOSE;
|
return expanded.value ? ICON_OPEN : ICON_CLOSE;
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDisabled = computed(() => {
|
const isDisabled = computed(() => {
|
||||||
|
@ -97,24 +130,22 @@ export default defineComponent({
|
||||||
return treeSelectable;
|
return treeSelectable;
|
||||||
});
|
});
|
||||||
const renderArgsData = computed(() => {
|
const renderArgsData = computed(() => {
|
||||||
|
const { data, active, checkable, disableCheckbox, disabled, selectable } = props;
|
||||||
return {
|
return {
|
||||||
...pick(props, [
|
active,
|
||||||
'active',
|
checkable,
|
||||||
'checkable',
|
disableCheckbox,
|
||||||
'checked',
|
disabled,
|
||||||
'disableCheckbox',
|
selectable,
|
||||||
'disabled',
|
...data,
|
||||||
'expanded',
|
dataRef: data,
|
||||||
'isLeaf',
|
data,
|
||||||
'loading',
|
|
||||||
'selectable',
|
|
||||||
'selected',
|
|
||||||
'halfChecked',
|
|
||||||
]),
|
|
||||||
...props.data,
|
|
||||||
dataRef: props.data,
|
|
||||||
data: props.data,
|
|
||||||
isLeaf: isLeaf.value,
|
isLeaf: isLeaf.value,
|
||||||
|
checked: checked.value,
|
||||||
|
expanded: expanded.value,
|
||||||
|
loading: loading.value,
|
||||||
|
selected: selected.value,
|
||||||
|
halfChecked: halfChecked.value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const instance = getCurrentInstance();
|
const instance = getCurrentInstance();
|
||||||
|
@ -122,13 +153,16 @@ export default defineComponent({
|
||||||
const { eventKey } = props;
|
const { eventKey } = props;
|
||||||
const { keyEntities } = context.value;
|
const { keyEntities } = context.value;
|
||||||
const { parent } = keyEntities[eventKey] || {};
|
const { parent } = keyEntities[eventKey] || {};
|
||||||
return { ...convertNodePropsToEventData(props), parent };
|
return {
|
||||||
|
...convertNodePropsToEventData(Object.assign({}, props, mergedTreeNodeProps.value)),
|
||||||
|
parent,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
const dragNodeEvent: DragNodeEvent = reactive({
|
const dragNodeEvent: DragNodeEvent = reactive({
|
||||||
eventData,
|
eventData,
|
||||||
eventKey: computed(() => props.eventKey),
|
eventKey: computed(() => props.eventKey),
|
||||||
selectHandle,
|
selectHandle,
|
||||||
pos: computed(() => props.pos),
|
pos,
|
||||||
key: instance.vnode.key as Key,
|
key: instance.vnode.key as Key,
|
||||||
});
|
});
|
||||||
expose(dragNodeEvent);
|
expose(dragNodeEvent);
|
||||||
|
@ -148,13 +182,13 @@ export default defineComponent({
|
||||||
const onCheck = (e: MouseEvent) => {
|
const onCheck = (e: MouseEvent) => {
|
||||||
if (isDisabled.value) return;
|
if (isDisabled.value) return;
|
||||||
|
|
||||||
const { disableCheckbox, checked } = props;
|
const { disableCheckbox } = props;
|
||||||
const { onNodeCheck } = context.value;
|
const { onNodeCheck } = context.value;
|
||||||
|
|
||||||
if (!isCheckable.value || disableCheckbox) return;
|
if (!isCheckable.value || disableCheckbox) return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const targetChecked = !checked;
|
const targetChecked = !checked.value;
|
||||||
onNodeCheck(e, eventData.value, targetChecked);
|
onNodeCheck(e, eventData.value, targetChecked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,7 +278,7 @@ export default defineComponent({
|
||||||
// Disabled item still can be switch
|
// Disabled item still can be switch
|
||||||
const onExpand = e => {
|
const onExpand = e => {
|
||||||
const { onNodeExpand } = context.value;
|
const { onNodeExpand } = context.value;
|
||||||
if (props.loading) return;
|
if (loading.value) return;
|
||||||
onNodeExpand(e, eventData.value);
|
onNodeExpand(e, eventData.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -279,18 +313,18 @@ export default defineComponent({
|
||||||
|
|
||||||
// Load data to avoid default expanded tree without data
|
// Load data to avoid default expanded tree without data
|
||||||
const syncLoadData = () => {
|
const syncLoadData = () => {
|
||||||
const { expanded, loading, loaded } = props;
|
//const { expanded, loading, loaded } = props;
|
||||||
const { loadData, onNodeLoad } = context.value;
|
const { loadData, onNodeLoad } = context.value;
|
||||||
|
|
||||||
if (loading) {
|
if (loading.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read from state to avoid loadData at same time
|
// read from state to avoid loadData at same time
|
||||||
if (loadData && expanded && !isLeaf.value) {
|
if (loadData && expanded.value && !isLeaf.value) {
|
||||||
// We needn't reload data when has children in sync logic
|
// We needn't reload data when has children in sync logic
|
||||||
// It's only needed in node expanded
|
// It's only needed in node expanded
|
||||||
if (!hasChildren.value && !loaded) {
|
if (!hasChildren.value && !loaded.value) {
|
||||||
onNodeLoad(eventData.value);
|
onNodeLoad(eventData.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,7 +340,6 @@ export default defineComponent({
|
||||||
|
|
||||||
// Switcher
|
// Switcher
|
||||||
const renderSwitcher = () => {
|
const renderSwitcher = () => {
|
||||||
const { expanded } = props;
|
|
||||||
const { prefixCls } = context.value;
|
const { prefixCls } = context.value;
|
||||||
// if switcherIconDom is null, no render switcher span
|
// if switcherIconDom is null, no render switcher span
|
||||||
const switcherIconDom = renderSwitcherIconDom();
|
const switcherIconDom = renderSwitcherIconDom();
|
||||||
|
@ -320,7 +353,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const switcherCls = classNames(
|
const switcherCls = classNames(
|
||||||
`${prefixCls}-switcher`,
|
`${prefixCls}-switcher`,
|
||||||
`${prefixCls}-switcher_${expanded ? ICON_OPEN : ICON_CLOSE}`,
|
`${prefixCls}-switcher_${expanded.value ? ICON_OPEN : ICON_CLOSE}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return switcherIconDom !== false ? (
|
return switcherIconDom !== false ? (
|
||||||
|
@ -332,7 +365,7 @@ export default defineComponent({
|
||||||
|
|
||||||
// Checkbox
|
// Checkbox
|
||||||
const renderCheckbox = () => {
|
const renderCheckbox = () => {
|
||||||
const { checked, halfChecked, disableCheckbox } = props;
|
const { disableCheckbox } = props;
|
||||||
const { prefixCls } = context.value;
|
const { prefixCls } = context.value;
|
||||||
|
|
||||||
const disabled = isDisabled.value;
|
const disabled = isDisabled.value;
|
||||||
|
@ -344,8 +377,8 @@ export default defineComponent({
|
||||||
<span
|
<span
|
||||||
class={classNames(
|
class={classNames(
|
||||||
`${prefixCls}-checkbox`,
|
`${prefixCls}-checkbox`,
|
||||||
checked && `${prefixCls}-checkbox-checked`,
|
checked.value && `${prefixCls}-checkbox-checked`,
|
||||||
!checked && halfChecked && `${prefixCls}-checkbox-indeterminate`,
|
!checked.value && halfChecked.value && `${prefixCls}-checkbox-indeterminate`,
|
||||||
(disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`,
|
(disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`,
|
||||||
)}
|
)}
|
||||||
onClick={onCheck}
|
onClick={onCheck}
|
||||||
|
@ -356,7 +389,6 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderIcon = () => {
|
const renderIcon = () => {
|
||||||
const { loading } = props;
|
|
||||||
const { prefixCls } = context.value;
|
const { prefixCls } = context.value;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -364,7 +396,7 @@ export default defineComponent({
|
||||||
class={classNames(
|
class={classNames(
|
||||||
`${prefixCls}-iconEle`,
|
`${prefixCls}-iconEle`,
|
||||||
`${prefixCls}-icon__${nodeState.value || 'docu'}`,
|
`${prefixCls}-icon__${nodeState.value || 'docu'}`,
|
||||||
loading && `${prefixCls}-icon_loading`,
|
loading.value && `${prefixCls}-icon_loading`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -396,9 +428,9 @@ export default defineComponent({
|
||||||
// title = slots.title ||
|
// title = slots.title ||
|
||||||
// context.value.slots?.[props.data?.slots?.title] ||
|
// context.value.slots?.[props.data?.slots?.title] ||
|
||||||
// context.value.slots?.title,
|
// context.value.slots?.title,
|
||||||
selected,
|
// selected,
|
||||||
icon = slots.icon,
|
icon = slots.icon,
|
||||||
loading,
|
// loading,
|
||||||
data,
|
data,
|
||||||
} = props;
|
} = props;
|
||||||
const title =
|
const title =
|
||||||
|
@ -430,7 +462,7 @@ export default defineComponent({
|
||||||
) : (
|
) : (
|
||||||
renderIcon()
|
renderIcon()
|
||||||
);
|
);
|
||||||
} else if (loadData && loading) {
|
} else if (loadData && loading.value) {
|
||||||
$icon = renderIcon();
|
$icon = renderIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +486,9 @@ export default defineComponent({
|
||||||
class={classNames(
|
class={classNames(
|
||||||
`${wrapClass}`,
|
`${wrapClass}`,
|
||||||
`${wrapClass}-${nodeState.value || 'normal'}`,
|
`${wrapClass}-${nodeState.value || 'normal'}`,
|
||||||
!disabled && (selected || dragNodeHighlight.value) && `${prefixCls}-node-selected`,
|
!disabled &&
|
||||||
|
(selected.value || dragNodeHighlight.value) &&
|
||||||
|
`${prefixCls}-node-selected`,
|
||||||
)}
|
)}
|
||||||
onMouseenter={onMouseEnter}
|
onMouseenter={onMouseEnter}
|
||||||
onMouseleave={onMouseLeave}
|
onMouseleave={onMouseLeave}
|
||||||
|
@ -471,17 +505,9 @@ export default defineComponent({
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
eventKey,
|
eventKey,
|
||||||
dragOver,
|
|
||||||
dragOverGapTop,
|
|
||||||
dragOverGapBottom,
|
|
||||||
isLeaf,
|
isLeaf,
|
||||||
isStart,
|
isStart,
|
||||||
isEnd,
|
isEnd,
|
||||||
expanded,
|
|
||||||
selected,
|
|
||||||
checked,
|
|
||||||
halfChecked,
|
|
||||||
loading,
|
|
||||||
domRef,
|
domRef,
|
||||||
active,
|
active,
|
||||||
data,
|
data,
|
||||||
|
@ -507,17 +533,17 @@ export default defineComponent({
|
||||||
|
|
||||||
const dragging = draggingNodeKey === eventKey;
|
const dragging = draggingNodeKey === eventKey;
|
||||||
const ariaSelected = selectable !== undefined ? { 'aria-selected': !!selectable } : undefined;
|
const ariaSelected = selectable !== undefined ? { 'aria-selected': !!selectable } : undefined;
|
||||||
|
// console.log(1);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={domRef}
|
ref={domRef}
|
||||||
class={classNames(attrs.class, `${prefixCls}-treenode`, {
|
class={classNames(attrs.class, `${prefixCls}-treenode`, {
|
||||||
[`${prefixCls}-treenode-disabled`]: disabled,
|
[`${prefixCls}-treenode-disabled`]: disabled,
|
||||||
[`${prefixCls}-treenode-switcher-${expanded ? 'open' : 'close'}`]: !isLeaf,
|
[`${prefixCls}-treenode-switcher-${expanded.value ? 'open' : 'close'}`]: !isLeaf,
|
||||||
[`${prefixCls}-treenode-checkbox-checked`]: checked,
|
[`${prefixCls}-treenode-checkbox-checked`]: checked.value,
|
||||||
[`${prefixCls}-treenode-checkbox-indeterminate`]: halfChecked,
|
[`${prefixCls}-treenode-checkbox-indeterminate`]: halfChecked.value,
|
||||||
[`${prefixCls}-treenode-selected`]: selected,
|
[`${prefixCls}-treenode-selected`]: selected.value,
|
||||||
[`${prefixCls}-treenode-loading`]: loading,
|
[`${prefixCls}-treenode-loading`]: loading.value,
|
||||||
[`${prefixCls}-treenode-active`]: active,
|
[`${prefixCls}-treenode-active`]: active,
|
||||||
[`${prefixCls}-treenode-leaf-last`]: isEndNode,
|
[`${prefixCls}-treenode-leaf-last`]: isEndNode,
|
||||||
[`${prefixCls}-treenode-draggable`]: draggableWithoutDisabled,
|
[`${prefixCls}-treenode-draggable`]: draggableWithoutDisabled,
|
||||||
|
@ -525,9 +551,9 @@ export default defineComponent({
|
||||||
dragging,
|
dragging,
|
||||||
'drop-target': dropTargetKey === eventKey,
|
'drop-target': dropTargetKey === eventKey,
|
||||||
'drop-container': dropContainerKey === eventKey,
|
'drop-container': dropContainerKey === eventKey,
|
||||||
'drag-over': !disabled && dragOver,
|
'drag-over': !disabled && dragOver.value,
|
||||||
'drag-over-gap-top': !disabled && dragOverGapTop,
|
'drag-over-gap-top': !disabled && dragOverGapTop.value,
|
||||||
'drag-over-gap-bottom': !disabled && dragOverGapBottom,
|
'drag-over-gap-bottom': !disabled && dragOverGapBottom.value,
|
||||||
'filter-node': filterTreeNode && filterTreeNode(eventData.value),
|
'filter-node': filterTreeNode && filterTreeNode(eventData.value),
|
||||||
})}
|
})}
|
||||||
style={attrs.style}
|
style={attrs.style}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
* When util.js imports the TreeNode for tree generate will cause treeContextTypes be empty.
|
* When util.js imports the TreeNode for tree generate will cause treeContextTypes be empty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ComputedRef, InjectionKey, PropType } from 'vue';
|
import type { ComputedRef, InjectionKey, PropType, ShallowRef } from 'vue';
|
||||||
import { inject, computed, defineComponent, provide } from 'vue';
|
import { shallowRef, inject, computed, defineComponent, provide } from 'vue';
|
||||||
import type { VueNode } from '../_util/type';
|
import type { VueNode } from '../_util/type';
|
||||||
import type {
|
import type {
|
||||||
IconType,
|
IconType,
|
||||||
|
@ -13,6 +13,7 @@ import type {
|
||||||
EventDataNode,
|
EventDataNode,
|
||||||
DragNodeEvent,
|
DragNodeEvent,
|
||||||
Direction,
|
Direction,
|
||||||
|
FlattenNode,
|
||||||
} from './interface';
|
} from './interface';
|
||||||
|
|
||||||
import type { DraggableConfig } from './Tree';
|
import type { DraggableConfig } from './Tree';
|
||||||
|
@ -60,6 +61,7 @@ export interface TreeContextProps {
|
||||||
direction: Direction;
|
direction: Direction;
|
||||||
}) => VueNode;
|
}) => VueNode;
|
||||||
dragOverNodeKey: Key | null;
|
dragOverNodeKey: Key | null;
|
||||||
|
dragging: boolean;
|
||||||
direction: Direction;
|
direction: Direction;
|
||||||
|
|
||||||
loadData: (treeNode: EventDataNode) => Promise<void>;
|
loadData: (treeNode: EventDataNode) => Promise<void>;
|
||||||
|
@ -108,3 +110,40 @@ export const useInjectTreeContext = () => {
|
||||||
computed(() => ({} as TreeContextProps)),
|
computed(() => ({} as TreeContextProps)),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
type KeysStateKeyType = {
|
||||||
|
expandedKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
selectedKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
loadedKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
loadingKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
checkedKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
halfCheckedKeysSet: ComputedRef<Set<Key>>;
|
||||||
|
expandedKeys: ShallowRef<Key[]>;
|
||||||
|
selectedKeys: ShallowRef<Key[]>;
|
||||||
|
loadedKeys: ShallowRef<Key[]>;
|
||||||
|
loadingKeys: ShallowRef<Key[]>;
|
||||||
|
checkedKeys: ShallowRef<Key[]>;
|
||||||
|
halfCheckedKeys: ShallowRef<Key[]>;
|
||||||
|
flattenNodes: ShallowRef<FlattenNode[]>;
|
||||||
|
};
|
||||||
|
const KeysStateKey: InjectionKey<KeysStateKeyType> = Symbol('KeysStateKey');
|
||||||
|
export const useProvideKeysState = (state: KeysStateKeyType) => {
|
||||||
|
provide(KeysStateKey, state);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useInjectKeysState = () => {
|
||||||
|
return inject(KeysStateKey, {
|
||||||
|
expandedKeys: shallowRef<Key[]>([]),
|
||||||
|
selectedKeys: shallowRef<Key[]>([]),
|
||||||
|
loadedKeys: shallowRef<Key[]>([]),
|
||||||
|
loadingKeys: shallowRef<Key[]>([]),
|
||||||
|
checkedKeys: shallowRef<Key[]>([]),
|
||||||
|
halfCheckedKeys: shallowRef<Key[]>([]),
|
||||||
|
expandedKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
selectedKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
loadedKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
loadingKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
checkedKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
halfCheckedKeysSet: computed<Set<Key>>(() => new Set()),
|
||||||
|
flattenNodes: shallowRef<FlattenNode[]>([]),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -7,15 +7,7 @@ import type {
|
||||||
NodeMouseEventHandler,
|
NodeMouseEventHandler,
|
||||||
NodeMouseEventParams,
|
NodeMouseEventParams,
|
||||||
} from './contextTypes';
|
} from './contextTypes';
|
||||||
import type {
|
import type { DataNode, Key, FlattenNode, EventDataNode, Direction, FieldNames } from './interface';
|
||||||
DataNode,
|
|
||||||
Key,
|
|
||||||
FlattenNode,
|
|
||||||
EventDataNode,
|
|
||||||
Direction,
|
|
||||||
FieldNames,
|
|
||||||
DataEntity,
|
|
||||||
} from './interface';
|
|
||||||
|
|
||||||
export interface CheckInfo {
|
export interface CheckInfo {
|
||||||
event: 'check';
|
event: 'check';
|
||||||
|
@ -32,18 +24,18 @@ export const treeNodeProps = {
|
||||||
prefixCls: String,
|
prefixCls: String,
|
||||||
|
|
||||||
// By parent
|
// By parent
|
||||||
expanded: { type: Boolean, default: undefined },
|
// expanded: { type: Boolean, default: undefined },
|
||||||
selected: { type: Boolean, default: undefined },
|
// selected: { type: Boolean, default: undefined },
|
||||||
checked: { type: Boolean, default: undefined },
|
// checked: { type: Boolean, default: undefined },
|
||||||
loaded: { type: Boolean, default: undefined },
|
// loaded: { type: Boolean, default: undefined },
|
||||||
loading: { type: Boolean, default: undefined },
|
// loading: { type: Boolean, default: undefined },
|
||||||
halfChecked: { type: Boolean, default: undefined },
|
// halfChecked: { type: Boolean, default: undefined },
|
||||||
title: PropTypes.any,
|
// dragOver: { type: Boolean, default: undefined },
|
||||||
dragOver: { type: Boolean, default: undefined },
|
// dragOverGapTop: { type: Boolean, default: undefined },
|
||||||
dragOverGapTop: { type: Boolean, default: undefined },
|
// dragOverGapBottom: { type: Boolean, default: undefined },
|
||||||
dragOverGapBottom: { type: Boolean, default: undefined },
|
// pos: String,
|
||||||
pos: String,
|
|
||||||
|
|
||||||
|
title: PropTypes.any,
|
||||||
/** New added in Tree for easy data access */
|
/** New added in Tree for easy data access */
|
||||||
data: { type: Object as PropType<DataNode>, default: undefined as DataNode },
|
data: { type: Object as PropType<DataNode>, default: undefined as DataNode },
|
||||||
parent: { type: Object as PropType<DataNode>, default: undefined as DataNode },
|
parent: { type: Object as PropType<DataNode>, default: undefined as DataNode },
|
||||||
|
@ -68,7 +60,7 @@ export type TreeNodeProps = Partial<ExtractPropTypes<typeof treeNodeProps>>;
|
||||||
|
|
||||||
export const nodeListProps = {
|
export const nodeListProps = {
|
||||||
prefixCls: { type: String as PropType<string> },
|
prefixCls: { type: String as PropType<string> },
|
||||||
data: { type: Array as PropType<FlattenNode[]> },
|
// data: { type: Array as PropType<FlattenNode[]> },
|
||||||
motion: { type: Object as PropType<any> },
|
motion: { type: Object as PropType<any> },
|
||||||
focusable: { type: Boolean as PropType<boolean> },
|
focusable: { type: Boolean as PropType<boolean> },
|
||||||
activeItem: { type: Object as PropType<FlattenNode> },
|
activeItem: { type: Object as PropType<FlattenNode> },
|
||||||
|
@ -78,17 +70,17 @@ export const nodeListProps = {
|
||||||
selectable: { type: Boolean as PropType<boolean> },
|
selectable: { type: Boolean as PropType<boolean> },
|
||||||
disabled: { type: Boolean as PropType<boolean> },
|
disabled: { type: Boolean as PropType<boolean> },
|
||||||
|
|
||||||
expandedKeys: { type: Array as PropType<Key[]> },
|
// expandedKeys: { type: Array as PropType<Key[]> },
|
||||||
selectedKeys: { type: Array as PropType<Key[]> },
|
// selectedKeys: { type: Array as PropType<Key[]> },
|
||||||
checkedKeys: { type: Array as PropType<Key[]> },
|
// checkedKeys: { type: Array as PropType<Key[]> },
|
||||||
loadedKeys: { type: Array as PropType<Key[]> },
|
// loadedKeys: { type: Array as PropType<Key[]> },
|
||||||
loadingKeys: { type: Array as PropType<Key[]> },
|
// loadingKeys: { type: Array as PropType<Key[]> },
|
||||||
halfCheckedKeys: { type: Array as PropType<Key[]> },
|
// halfCheckedKeys: { type: Array as PropType<Key[]> },
|
||||||
keyEntities: { type: Object as PropType<Record<Key, DataEntity<DataNode>>> },
|
// keyEntities: { type: Object as PropType<Record<Key, DataEntity<DataNode>>> },
|
||||||
|
|
||||||
dragging: { type: Boolean as PropType<boolean> },
|
// dragging: { type: Boolean as PropType<boolean> },
|
||||||
dragOverNodeKey: { type: [String, Number] as PropType<Key> },
|
// dragOverNodeKey: { type: [String, Number] as PropType<Key> },
|
||||||
dropPosition: { type: Number as PropType<number> },
|
// dropPosition: { type: Number as PropType<number> },
|
||||||
|
|
||||||
// Virtual list
|
// Virtual list
|
||||||
height: { type: Number as PropType<number> },
|
height: { type: Number as PropType<number> },
|
||||||
|
|
|
@ -98,7 +98,7 @@ export function calcDropPosition<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
allowDrop: AllowDrop<TreeDataType>,
|
allowDrop: AllowDrop<TreeDataType>,
|
||||||
flattenedNodes: FlattenNode[],
|
flattenedNodes: FlattenNode[],
|
||||||
keyEntities: Record<Key, DataEntity<TreeDataType>>,
|
keyEntities: Record<Key, DataEntity<TreeDataType>>,
|
||||||
expandKeys: Key[],
|
expandKeysSet: Set<Key>,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
): {
|
): {
|
||||||
dropPosition: -1 | 0 | 1;
|
dropPosition: -1 | 0 | 1;
|
||||||
|
@ -138,7 +138,7 @@ export function calcDropPosition<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
let dropLevelOffset = 0;
|
let dropLevelOffset = 0;
|
||||||
|
|
||||||
// Only allow cross level drop when dragging on a non-expanded node
|
// Only allow cross level drop when dragging on a non-expanded node
|
||||||
if (!expandKeys.includes(initialAbstractDropNodeKey)) {
|
if (!expandKeysSet.has(initialAbstractDropNodeKey)) {
|
||||||
for (let i = 0; i < rawDropLevelOffset; i += 1) {
|
for (let i = 0; i < rawDropLevelOffset; i += 1) {
|
||||||
if (isLastChild(abstractDropNodeEntity)) {
|
if (isLastChild(abstractDropNodeEntity)) {
|
||||||
abstractDropNodeEntity = abstractDropNodeEntity.parent;
|
abstractDropNodeEntity = abstractDropNodeEntity.parent;
|
||||||
|
@ -164,10 +164,7 @@ export function calcDropPosition<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
) {
|
) {
|
||||||
// first half of first node in first level
|
// first half of first node in first level
|
||||||
dropPosition = -1;
|
dropPosition = -1;
|
||||||
} else if (
|
} else if ((abstractDragOverEntity.children || []).length && expandKeysSet.has(dragOverNodeKey)) {
|
||||||
(abstractDragOverEntity.children || []).length &&
|
|
||||||
expandKeys.includes(dragOverNodeKey)
|
|
||||||
) {
|
|
||||||
// drop on expanded node
|
// drop on expanded node
|
||||||
// only allow drop inside
|
// only allow drop inside
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -361,12 +361,12 @@ export function convertDataToEntities(
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TreeNodeRequiredProps<TreeDataType extends BasicDataNode = DataNode> {
|
export interface TreeNodeRequiredProps<TreeDataType extends BasicDataNode = DataNode> {
|
||||||
expandedKeys: Key[];
|
expandedKeysSet: Set<Key>;
|
||||||
selectedKeys: Key[];
|
selectedKeysSet: Set<Key>;
|
||||||
loadedKeys: Key[];
|
loadedKeysSet: Set<Key>;
|
||||||
loadingKeys: Key[];
|
loadingKeysSet: Set<Key>;
|
||||||
checkedKeys: Key[];
|
checkedKeysSet: Set<Key>;
|
||||||
halfCheckedKeys: Key[];
|
halfCheckedKeysSet: Set<Key>;
|
||||||
dragOverNodeKey: Key;
|
dragOverNodeKey: Key;
|
||||||
dropPosition: number;
|
dropPosition: number;
|
||||||
keyEntities: Record<Key, DataEntity<TreeDataType>>;
|
keyEntities: Record<Key, DataEntity<TreeDataType>>;
|
||||||
|
@ -378,12 +378,12 @@ export interface TreeNodeRequiredProps<TreeDataType extends BasicDataNode = Data
|
||||||
export function getTreeNodeProps<TreeDataType extends BasicDataNode = DataNode>(
|
export function getTreeNodeProps<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
key: Key,
|
key: Key,
|
||||||
{
|
{
|
||||||
expandedKeys,
|
expandedKeysSet,
|
||||||
selectedKeys,
|
selectedKeysSet,
|
||||||
loadedKeys,
|
loadedKeysSet,
|
||||||
loadingKeys,
|
loadingKeysSet,
|
||||||
checkedKeys,
|
checkedKeysSet,
|
||||||
halfCheckedKeys,
|
halfCheckedKeysSet,
|
||||||
dragOverNodeKey,
|
dragOverNodeKey,
|
||||||
dropPosition,
|
dropPosition,
|
||||||
keyEntities,
|
keyEntities,
|
||||||
|
@ -393,12 +393,12 @@ export function getTreeNodeProps<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
|
|
||||||
const treeNodeProps = {
|
const treeNodeProps = {
|
||||||
eventKey: key,
|
eventKey: key,
|
||||||
expanded: expandedKeys.indexOf(key) !== -1,
|
expanded: expandedKeysSet.has(key),
|
||||||
selected: selectedKeys.indexOf(key) !== -1,
|
selected: selectedKeysSet.has(key),
|
||||||
loaded: loadedKeys.indexOf(key) !== -1,
|
loaded: loadedKeysSet.has(key),
|
||||||
loading: loadingKeys.indexOf(key) !== -1,
|
loading: loadingKeysSet.has(key),
|
||||||
checked: checkedKeys.indexOf(key) !== -1,
|
checked: checkedKeysSet.has(key),
|
||||||
halfChecked: halfCheckedKeys.indexOf(key) !== -1,
|
halfChecked: halfCheckedKeysSet.has(key),
|
||||||
pos: String(entity ? entity.pos : ''),
|
pos: String(entity ? entity.pos : ''),
|
||||||
parent: entity.parent,
|
parent: entity.parent,
|
||||||
// [Legacy] Drag props
|
// [Legacy] Drag props
|
||||||
|
@ -412,7 +412,9 @@ export function getTreeNodeProps<TreeDataType extends BasicDataNode = DataNode>(
|
||||||
return treeNodeProps;
|
return treeNodeProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertNodePropsToEventData(props: TreeNodeProps): EventDataNode {
|
export function convertNodePropsToEventData(
|
||||||
|
props: TreeNodeProps & ReturnType<typeof getTreeNodeProps>,
|
||||||
|
): EventDataNode {
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
expanded,
|
expanded,
|
||||||
|
|
Loading…
Reference in New Issue