mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-03 04:27:41 +08:00
f0385d7c24
* feat: tree * refactor: select * refactor: select * refactor: select * refactor: vc-tree-select * refactor: tree-select * refactor: tree-select * feat: add showLeafIcon * refactor: remove lod vc-tree-select * feat: tree-select add tag-render * refactor: cascader * refactor: cascader * refactor: cascader * refactor: cascader * fix: maxTagmaxTagPlaceholder not work
255 lines
8.0 KiB
Vue
255 lines
8.0 KiB
Vue
import type { PropType, ExtractPropTypes } from 'vue';
|
||
import { watchEffect, ref, defineComponent, computed } from 'vue';
|
||
import classNames from '../_util/classNames';
|
||
import VcTree from '../vc-tree';
|
||
import PropTypes from '../_util/vue-types';
|
||
import { filterEmpty } from '../_util/props-util';
|
||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||
import type { DataNode, EventDataNode, FieldNames, Key } from '../vc-tree/interface';
|
||
import type { TreeNodeProps } from '../vc-tree/props';
|
||
import { treeProps as vcTreeProps } from '../vc-tree/props';
|
||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||
import renderSwitcherIcon from './utils/iconUtil';
|
||
import dropIndicatorRender from './utils/dropIndicator';
|
||
import devWarning from '../vc-util/devWarning';
|
||
import { warning } from '../vc-util/warning';
|
||
|
||
export interface AntdTreeNodeAttribute {
|
||
eventKey: string;
|
||
prefixCls: string;
|
||
class: string;
|
||
expanded: boolean;
|
||
selected: boolean;
|
||
checked: boolean;
|
||
halfChecked: boolean;
|
||
children: any;
|
||
title: any;
|
||
pos: string;
|
||
dragOver: boolean;
|
||
dragOverGapTop: boolean;
|
||
dragOverGapBottom: boolean;
|
||
isLeaf: boolean;
|
||
selectable: boolean;
|
||
disabled: boolean;
|
||
disableCheckbox: boolean;
|
||
}
|
||
|
||
export type AntTreeNodeProps = TreeNodeProps;
|
||
|
||
// [Legacy] Compatible for v2
|
||
export type TreeDataItem = DataNode;
|
||
|
||
export interface AntTreeNodeBaseEvent {
|
||
node: EventDataNode;
|
||
nativeEvent: MouseEvent;
|
||
}
|
||
|
||
export interface AntTreeNodeCheckedEvent extends AntTreeNodeBaseEvent {
|
||
event: 'check';
|
||
checked?: boolean;
|
||
checkedNodes?: DataNode[];
|
||
}
|
||
|
||
export interface AntTreeNodeSelectedEvent extends AntTreeNodeBaseEvent {
|
||
event: 'select';
|
||
selected?: boolean;
|
||
selectedNodes?: DataNode[];
|
||
}
|
||
|
||
export interface AntTreeNodeExpandedEvent extends AntTreeNodeBaseEvent {
|
||
expanded?: boolean;
|
||
}
|
||
|
||
export interface AntTreeNodeMouseEvent {
|
||
node: EventDataNode;
|
||
event: DragEvent;
|
||
}
|
||
|
||
export interface AntTreeNodeDragEnterEvent extends AntTreeNodeMouseEvent {
|
||
expandedKeys: Key[];
|
||
}
|
||
|
||
export interface AntTreeNodeDropEvent {
|
||
node: EventDataNode;
|
||
dragNode: EventDataNode;
|
||
dragNodesKeys: Key[];
|
||
dropPosition: number;
|
||
dropToGap?: boolean;
|
||
event: MouseEvent;
|
||
}
|
||
|
||
export const treeProps = () => {
|
||
return {
|
||
...vcTreeProps(),
|
||
showLine: {
|
||
type: [Boolean, Object] as PropType<boolean | { showLeafIcon: boolean }>,
|
||
default: undefined,
|
||
},
|
||
/** 是否支持多选 */
|
||
multiple: { type: Boolean, default: undefined },
|
||
/** 是否自动展开父节点 */
|
||
autoExpandParent: { type: Boolean, default: undefined },
|
||
/** checkable状态下节点选择完全受控(父子节点选中状态不再关联)*/
|
||
checkStrictly: { type: Boolean, default: undefined },
|
||
/** 是否支持选中 */
|
||
checkable: { type: Boolean, default: undefined },
|
||
/** 是否禁用树 */
|
||
disabled: { type: Boolean, default: undefined },
|
||
/** 默认展开所有树节点 */
|
||
defaultExpandAll: { type: Boolean, default: undefined },
|
||
/** 默认展开对应树节点 */
|
||
defaultExpandParent: { type: Boolean, default: undefined },
|
||
/** 默认展开指定的树节点 */
|
||
defaultExpandedKeys: { type: Array as PropType<Key[]> },
|
||
/** (受控)展开指定的树节点 */
|
||
expandedKeys: { type: Array as PropType<Key[]> },
|
||
/** (受控)选中复选框的树节点 */
|
||
checkedKeys: {
|
||
type: [Array, Object] as PropType<Key[] | { checked: Key[]; halfChecked: Key[] }>,
|
||
},
|
||
/** 默认选中复选框的树节点 */
|
||
defaultCheckedKeys: { type: Array as PropType<Key[]> },
|
||
/** (受控)设置选中的树节点 */
|
||
selectedKeys: { type: Array as PropType<Key[]> },
|
||
/** 默认选中的树节点 */
|
||
defaultSelectedKeys: { type: Array as PropType<Key[]> },
|
||
selectable: { type: Boolean, default: undefined },
|
||
|
||
loadedKeys: { type: Array as PropType<Key[]> },
|
||
draggable: { type: Boolean, default: undefined },
|
||
showIcon: { type: Boolean, default: undefined },
|
||
icon: { type: Function as PropType<(nodeProps: AntdTreeNodeAttribute) => any> },
|
||
switcherIcon: PropTypes.any,
|
||
prefixCls: PropTypes.string,
|
||
/**
|
||
* @default{title,key,children}
|
||
* deprecated, please use `fieldNames` instead
|
||
* 替换treeNode中 title,key,children字段为treeData中对应的字段
|
||
*/
|
||
replaceFields: { type: Object as PropType<FieldNames> },
|
||
blockNode: { type: Boolean, default: undefined },
|
||
openAnimation: PropTypes.any,
|
||
};
|
||
};
|
||
|
||
export type TreeProps = Partial<ExtractPropTypes<ReturnType<typeof treeProps>>>;
|
||
|
||
export default defineComponent({
|
||
name: 'ATree',
|
||
inheritAttrs: false,
|
||
props: initDefaultProps(treeProps(), {
|
||
checkable: false,
|
||
selectable: true,
|
||
showIcon: false,
|
||
blockNode: false,
|
||
}),
|
||
slots: ['icon', 'title', 'switcherIcon', 'titleRender'],
|
||
emits: [
|
||
'update:selectedKeys',
|
||
'update:checkedKeys',
|
||
'update:expandedKeys',
|
||
'expand',
|
||
'select',
|
||
'check',
|
||
'doubleclick',
|
||
'dblclick',
|
||
],
|
||
setup(props, { attrs, expose, emit, slots }) {
|
||
warning(
|
||
!(props.treeData === undefined && slots.default),
|
||
'`children` of Tree is deprecated. Please use `treeData` instead.',
|
||
);
|
||
const { prefixCls, direction, virtual } = useConfigInject('tree', props);
|
||
const treeRef = ref();
|
||
expose({
|
||
treeRef,
|
||
onNodeExpand: (...args) => {
|
||
treeRef.value?.onNodeExpand(...args);
|
||
},
|
||
selectedKeys: computed(() => treeRef.value?.selectedKeys),
|
||
checkedKeys: computed(() => treeRef.value?.checkedKeys),
|
||
halfCheckedKeys: computed(() => treeRef.value?.halfCheckedKeys),
|
||
loadedKeys: computed(() => treeRef.value?.loadedKeys),
|
||
loadingKeys: computed(() => treeRef.value?.loadingKeys),
|
||
expandedKeys: computed(() => treeRef.value?.expandedKeys),
|
||
});
|
||
|
||
watchEffect(() => {
|
||
devWarning(
|
||
props.replaceFields === undefined,
|
||
'Tree',
|
||
'`replaceFields` is deprecated, please use fieldNames instead',
|
||
);
|
||
});
|
||
|
||
const handleCheck: TreeProps['onCheck'] = (checkedObjOrKeys, eventObj) => {
|
||
emit('update:checkedKeys', checkedObjOrKeys);
|
||
emit('check', checkedObjOrKeys, eventObj);
|
||
};
|
||
const handleExpand: TreeProps['onExpand'] = (expandedKeys, eventObj) => {
|
||
emit('update:expandedKeys', expandedKeys);
|
||
emit('expand', expandedKeys, eventObj);
|
||
};
|
||
const handleSelect: TreeProps['onSelect'] = (selectedKeys, eventObj) => {
|
||
emit('update:selectedKeys', selectedKeys);
|
||
emit('select', selectedKeys, eventObj);
|
||
};
|
||
return () => {
|
||
const {
|
||
showIcon,
|
||
showLine,
|
||
switcherIcon = slots.switcherIcon,
|
||
icon = slots.icon,
|
||
blockNode,
|
||
checkable,
|
||
selectable,
|
||
fieldNames = props.replaceFields,
|
||
motion = props.openAnimation,
|
||
itemHeight = 28,
|
||
} = props as TreeProps;
|
||
const newProps = {
|
||
...attrs,
|
||
...props,
|
||
showLine: Boolean(showLine),
|
||
dropIndicatorRender,
|
||
fieldNames,
|
||
icon,
|
||
itemHeight,
|
||
};
|
||
|
||
return (
|
||
<VcTree
|
||
{...newProps}
|
||
virtual={virtual.value}
|
||
motion={motion}
|
||
ref={treeRef}
|
||
prefixCls={prefixCls.value}
|
||
class={classNames(
|
||
{
|
||
[`${prefixCls.value}-icon-hide`]: !showIcon,
|
||
[`${prefixCls.value}-block-node`]: blockNode,
|
||
[`${prefixCls.value}-unselectable`]: !selectable,
|
||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||
},
|
||
attrs.class,
|
||
)}
|
||
direction={direction.value}
|
||
checkable={checkable}
|
||
selectable={selectable}
|
||
switcherIcon={(nodeProps: AntTreeNodeProps) =>
|
||
renderSwitcherIcon(prefixCls.value, switcherIcon, showLine, nodeProps)
|
||
}
|
||
onCheck={handleCheck}
|
||
onExpand={handleExpand}
|
||
onSelect={handleSelect}
|
||
v-slots={{
|
||
...slots,
|
||
checkable: () => <span class={`${prefixCls.value}-checkbox-inner`} />,
|
||
}}
|
||
children={filterEmpty(slots.default?.())}
|
||
></VcTree>
|
||
);
|
||
};
|
||
},
|
||
});
|