UNPKG

vue-tree-kl

Version:

A vue tree component using virtual list.

298 lines (291 loc) 8.98 kB
import { ref } from 'vue' import { AnyPropsArrayType, INonReactiveData, IgnoreType, TreeNodeKeyType } from '../types' import { TreeNode } from '..' import { ITreeNodeOptions } from '../store/tree-node' import { FilterFunctionType } from '../store/tree-store' import { TreeProps } from '../components/Tree.vue' type IUsePublicTreeAPIProps = Required< Pick< TreeProps, | 'selectable' | 'checkable' | 'showExpand' | 'separator' | 'ignoreMode' | 'titleField' | 'keyField' | 'showUnloadCheckedNodes' | 'showExpand' | 'unloadDataList' > > & Pick<TreeProps, 'modelValue' | 'filterMethod' | 'load'> export const usePublicTreeAPI = ( nonReactive: INonReactiveData, props: IUsePublicTreeAPIProps, options: { resetSpaceHeights: () => void updateExpandedKeys: () => void updateBlockData: () => void updateRender: () => void } ) => { const { resetSpaceHeights, updateExpandedKeys, updateBlockData, updateRender } = options const unloadCheckedNodes = ref<TreeNode[]>([]) const isRootLoading = ref(false) /** 使用此方法重置树数据,可避免大量数据被 vue 监听 */ function setData(data: AnyPropsArrayType): void { resetSpaceHeights() let checkableUnloadKeys: TreeNodeKeyType | TreeNodeKeyType[] | null = null let selectableUnloadKey: TreeNodeKeyType | null = null if (props.checkable) { if (Array.isArray(props.modelValue)) { checkableUnloadKeys = props.modelValue.concat() } else if (typeof props.modelValue === 'string') { checkableUnloadKeys = props.modelValue === '' ? [] : props.modelValue.split(props.separator) } } else if (props.selectable && !Array.isArray(props.modelValue)) { selectableUnloadKey = props.modelValue as TreeNodeKeyType | null } nonReactive.store.setData( data, selectableUnloadKey, checkableUnloadKeys as TreeNodeKeyType[] ) updateExpandedKeys() } function setChecked(key: TreeNodeKeyType, value: boolean): void { nonReactive.store.setChecked(key, value) } function setCheckedKeys(keys: TreeNodeKeyType[], value: boolean): void { nonReactive.store.setCheckedKeys(keys, value) } function checkAll(): void { nonReactive.store.checkAll() } function clearChecked(): void { nonReactive.store.clearChecked() } function setSelected(key: TreeNodeKeyType, value: boolean): void { nonReactive.store.setSelected(key, value) } function clearSelected(): void { nonReactive.store.clearSelected() } function setExpand( key: TreeNodeKeyType, value: boolean, expandParent: boolean = true ): Promise<void> { return nonReactive.store.setExpand(key, value, expandParent) } function setExpandKeys(keys: TreeNodeKeyType[], value: boolean): void { nonReactive.store.setExpandKeys(keys, value) } function setExpandAll(value: boolean): void { nonReactive.store.setExpandAll(value) } function getCheckedNodes(ignoreMode?: IgnoreType): TreeNode[] { ignoreMode = ignoreMode || props.ignoreMode return nonReactive.store.getCheckedNodes(ignoreMode) } function getCheckedKeys(ignoreMode?: IgnoreType): TreeNodeKeyType[] { ignoreMode = ignoreMode || props.ignoreMode return nonReactive.store.getCheckedKeys(ignoreMode) } function getIndeterminateNodes(): TreeNode[] { return nonReactive.store.getIndeterminateNodes() } function getSelectedNode(): TreeNode | null { return nonReactive.store.getSelectedNode() } function getSelectedKey(): TreeNodeKeyType | null { return nonReactive.store.getSelectedKey() } function getExpandNodes(): TreeNode[] { return nonReactive.store.getExpandNodes() } function getExpandKeys(): TreeNodeKeyType[] { return nonReactive.store.getExpandKeys() } function getCurrentVisibleNodes(): TreeNode[] { return nonReactive.store.flatData.filter(node => node._filterVisible) } function getNode(key: TreeNodeKeyType): TreeNode | null { return nonReactive.store.getNode(key) } /** 返回树形结构的节点数据 */ function getTreeData(): TreeNode[] { return nonReactive.store.data } /** 返回扁平化后的节点数据 */ function getFlatData(): TreeNode[] { return nonReactive.store.flatData } function getNodesCount(): number { return nonReactive.store.flatData.length } function insertBefore( insertedNode: TreeNodeKeyType | ITreeNodeOptions, referenceKey: TreeNodeKeyType ): TreeNode | null { return nonReactive.store.insertBefore(insertedNode, referenceKey) } function insertAfter( insertedNode: TreeNodeKeyType | ITreeNodeOptions, referenceKey: TreeNodeKeyType ): TreeNode | null { return nonReactive.store.insertAfter(insertedNode, referenceKey) } function append( insertedNode: TreeNodeKeyType | ITreeNodeOptions, parentKey: TreeNodeKeyType ): TreeNode | null { return nonReactive.store.append(insertedNode, parentKey) } function prepend( insertedNode: TreeNodeKeyType | ITreeNodeOptions, parentKey: TreeNodeKeyType ): TreeNode | null { return nonReactive.store.prepend(insertedNode, parentKey) } function remove(removedKey: TreeNodeKeyType): TreeNode | null { return nonReactive.store.remove(removedKey) } function filter(keyword: string, filterMethod?: FilterFunctionType): void { const defaultFilterMethod = (keyword: string, node: TreeNode) => { const title = node[props.titleField] if (title == null || !title.toString) return false return ( (title.toString() as string) .toLowerCase() .indexOf(keyword.toLowerCase()) > -1 ) } const finalFilterMethod = filterMethod || props.filterMethod || defaultFilterMethod nonReactive.store.filter(keyword, finalFilterMethod) } /** * 展示已选节点 */ function showCheckedNodes(showUnloadCheckedNodes?: boolean): void { if (!props.checkable) return showUnloadCheckedNodes = showUnloadCheckedNodes == null ? props.showUnloadCheckedNodes : showUnloadCheckedNodes const checkedNodesCache = nonReactive.store.getCheckedNodes() nonReactive.store.filter('', (keyword, node) => node.checked) if (!showUnloadCheckedNodes) return const unloadKeys = nonReactive.store.getUnloadCheckedKeys() if (unloadKeys.length) { const unloadNodes: TreeNode[] = unloadKeys.map(key => { const queryList = props.unloadDataList.concat(checkedNodesCache) let title = key queryList.some((query: any) => { if ( query[props.keyField] === key && query[props.titleField] != null ) { title = query[props.titleField] return true } return false }) return new TreeNode( { [props.keyField]: key, [props.titleField]: title, checked: true, isLeaf: true }, null, props.keyField, !!props.load ) }) unloadCheckedNodes.value = unloadNodes as TreeNode[] nonReactive.blockNodes = nonReactive.blockNodes.concat(unloadNodes) updateBlockData() updateRender() } } /** * 从远程加载根节点 */ function loadRootNodes(): Promise<void> { isRootLoading.value = true return new Promise((resolve, reject) => { if (props.load) props.load(null, resolve, reject) }) .then(root => { if (Array.isArray(root)) { setData(root as AnyPropsArrayType) } }) .catch(() => {}) .then(() => { isRootLoading.value = false }) } /** * 更新单个节点 */ function updateNode(key: TreeNodeKeyType, newNode: ITreeNodeOptions) { return nonReactive.store.updateNode(key, newNode) } /** * 更新多个节点 */ function updateNodes(newNodes: ITreeNodeOptions[]) { return nonReactive.store.updateNodes(newNodes) } return { unloadCheckedNodes, isRootLoading, setData, setChecked, setCheckedKeys, checkAll, clearChecked, setSelected, clearSelected, setExpand, setExpandKeys, setExpandAll, getCheckedNodes, getCheckedKeys, getIndeterminateNodes, getSelectedNode, getSelectedKey, getExpandNodes, getExpandKeys, getCurrentVisibleNodes, getNode, getTreeData, getFlatData, getNodesCount, insertBefore, insertAfter, append, prepend, remove, filter, showCheckedNodes, loadRootNodes, updateNode, updateNodes } }