tdesign-mobile-vue
Version:
tdesign-mobile-vue
1 lines • 82.7 kB
Source Map (JSON)
{"version":3,"file":"tree-node.mjs","sources":["../../../../src/_common/js/tree/tree-node.ts"],"sourcesContent":["import isNull from 'lodash/isNull';\nimport isFunction from 'lodash/isFunction';\nimport isNumber from 'lodash/isNumber';\nimport uniqueId from 'lodash/uniqueId';\nimport isBoolean from 'lodash/isBoolean';\nimport isNil from 'lodash/isNil';\nimport get from 'lodash/get';\nimport { TreeStore } from './tree-store';\nimport {\n TreeNodeValue,\n TreeNodeState,\n TypeIdMap,\n TypeTreeItem,\n TypeSettingOptions,\n TypeTreeNodeModel,\n TypeTreeNodeData,\n TypeTreeStoreOptions,\n TypeFnOperation,\n} from './types';\nimport {\n createNodeModel,\n} from './tree-node-model';\nimport log from '../log';\n\nconst { hasOwnProperty } = Object.prototype;\n\n// 这里的属性为 data 中属性可以同步到 treeNode 实例属性的白名单\n// 仅 label 属性和在列表中的属性可以通过 set 方法配置到 treeNode 实例上\nexport const setableStatus: Record<string, boolean | null> = {\n expandMutex: null,\n activable: null,\n checkable: null,\n draggable: null,\n loading: false,\n};\n\nexport const setableProps = Object.keys(setableStatus);\n\nexport const syncableProps = [...setableProps, 'actived', 'expanded', 'checked'];\n\nexport const privateKey = '__tdesign_id__';\n\n// vm 开头为视图属性,不可以外部设置\n// 用于触发视图更新\n// public 方法,在 ui 组件中有可能在使用,会保障其输入输出实现\n// private 方法,可能会改动其输入输出\n\n/**\n * tree 节点数据模型\n * @class TreeNode\n * @param {TreeStore} tree TreeStore 实例\n * @param {object} [data] 节点数据\n * @param {TreeNode} parent 指定的当前 TreeStore 实例中的父节点\n */\nexport class TreeNode {\n // 节点隶属的树实例\n public tree: TreeStore;\n\n // 节点私有 id,不接受外部传入,确保唯一性\n public [privateKey]: string;\n\n // 节点 id ,唯一标志\n public value: string;\n\n // 节点文本\n public label: string;\n\n // 节点数据\n public data: TypeTreeNodeData;\n\n // 父节点\n public parent: TreeNode;\n\n // 子节点列表\n public children: TreeNode[] | boolean;\n\n // 暴露的 treeNodeModel,这个对象的属性和 api 提供给用户使用\n public model: TypeTreeNodeModel;\n\n // 是否为叶节点\n public vmIsLeaf: boolean;\n\n // 是否为子节点中的第一个\n public vmIsFirst: boolean;\n\n // 是否为子节点中的最后\n public vmIsLast: boolean;\n\n // 节点是否是经过过滤剩下的\n public vmIsRest: boolean;\n\n // 节点是否展示为锁定状态\n public vmIsLocked: boolean;\n\n // 节点在视图上实际的展开状态\n public expanded: boolean;\n\n // 展开时是否收起同级节点,对子节点生效\n public expandMutex: null | boolean;\n\n // 节点在视图上实际的激活状态\n public actived: boolean;\n\n // 是否可激活\n public activable: null | boolean;\n\n // 是否可选中\n public checkable: null | boolean;\n\n // 是否可选中的视图呈现\n public vmCheckable: boolean;\n\n // 节点在视图上实际的选中态\n public checked: boolean;\n\n // 节点实际是否为半选状态\n public indeterminate: boolean;\n\n // 节点是否已禁用\n public disabled: null | boolean;\n\n // 节点是否可拖动\n public draggable: null | boolean;\n\n // 节点是否可视\n public visible: boolean;\n\n // 节点在树中的层级\n public level: number;\n\n // 节点是否正在加载数据\n public loading: boolean;\n\n public constructor(\n tree: TreeStore,\n data?: TypeTreeNodeData,\n parent?: TreeNode,\n ) {\n this.data = data;\n this.tree = tree;\n\n const config = tree.config || {};\n const prefix = config.prefix || 't';\n const keys = config.keys || {};\n const propChildren = keys.children || 'children';\n const propLabel = keys.label || 'label';\n const propValue = keys.value || 'value';\n const propDisabled = keys.disabled || 'disabled';\n\n // 节点自身初始化数据\n this.model = null;\n this.children = null;\n this.level = 0;\n\n // vm 开头为视图属性,不可以外部设置\n this.vmCheckable = false;\n this.vmIsLeaf = false;\n this.vmIsFirst = false;\n this.vmIsLast = false;\n this.vmIsRest = false;\n this.vmIsLocked = false;\n\n // 初始化节点基本状态\n this.visible = false;\n this.actived = false;\n this.checked = false;\n this.indeterminate = false;\n this.loading = false;\n this.expanded = config.expandAll;\n\n // 下面几个属性,节点初始化的时候,可以设置与 treeStore.config 不同的值\n // 初始化默认值为 null, 则在方法判断时,默认以 treeStore.config 为准\n // 传递或者设置属性为 boolean 类型的值,则以节点属性值为准\n // 这种处理方式主要是解决 treeStore.setConfig 方法配置全局属性导致的状态切换与保留的问题\n this.activable = null;\n this.checkable = null;\n this.expandMutex = null;\n this.draggable = null;\n\n // 为节点设置唯一 id\n // tree 数据替换时,value 相同有可能导致节点状态渲染冲突\n // 用这个 唯一 id 来解决,用于类似 vue 组件的唯一 key 指定场景\n this[privateKey] = uniqueId(prefix);\n\n // 设置 value\n // 没有 value 的时候,value 默认使用自动生成的 唯一 id\n this.value = isNil(get(data, propValue))\n ? this[privateKey]\n : get(data, propValue);\n const { nodeMap, privateMap } = tree;\n if (nodeMap.get(this.value)) {\n log.warn('Tree', `Dulplicate value: ${this.value}`);\n }\n nodeMap.set(this.value, this);\n privateMap.set(this[privateKey], this);\n\n // 设置标签\n this.label = get(data, propLabel) || '';\n // 设置是否禁用\n this.disabled = get(data, propDisabled) || false;\n\n // 设置子节点\n const children = data[propChildren];\n // 子节点为 true 的状态逻辑需要放到状态计算之前\n // 初始化加载逻辑需要依据这个来进行\n if (children === true) {\n this.children = children;\n }\n\n // 设置父节点\n if (parent && parent instanceof TreeNode) {\n this.parent = parent;\n } else {\n this.parent = null;\n }\n\n // 同步数据属性到节点属性\n // 仅 syncableStatus 列举的属性被同步到 treeNode 实例属性\n syncableProps.forEach((prop) => {\n if (typeof data[prop] !== 'undefined') {\n this[prop] = data[prop];\n }\n });\n\n // 初始化节点激活状态\n this.initActived();\n // 展开状态影响了子节点的显示状态,所以要在子节点插入之前初始化展开状态\n this.initExpanded();\n\n // 这里的子节点加载逻辑不能放到状态初始化之前\n // 因为子节点状态计算依赖父节点初始化状态\n if (Array.isArray(children)) {\n this.append(children);\n } else if (children === true && !config.lazy) {\n this.loadChildren();\n }\n\n // 节点的选中状态同时依赖于子节点状态与父节点状态\n // 因此在子节点插入之后再更新选中状态\n this.initChecked();\n this.updateChecked();\n\n // 标记节点更新\n this.update();\n // 创建节点需要回流操作\n tree.reflow(this);\n }\n\n /* ------ 状态初始化 ------ */\n\n /**\n * 初始化选中态\n * @return void\n */\n private initChecked(): void {\n const { tree, value, parent } = this;\n const { checkedMap } = tree;\n const { checkStrictly } = tree.config;\n if (this.checked) {\n checkedMap.set(value, true);\n }\n // 这里不可以使用 parent.isChecked 方法\n // 因为当前节点创建时尚未插入父节点的 children 数组,可能父节点选中态仅受到之前子节点状态的影响\n // 这会导致父节点状态计算错误,进而引发子节点变更了选中状态\n if (!checkStrictly && parent?.checked) {\n checkedMap.set(value, true);\n }\n }\n\n /**\n * 初始化节点展开状态\n * @return void\n */\n private initExpanded(): void {\n const { tree } = this;\n let { expanded } = this;\n const { config } = tree;\n if (isNumber(config.expandLevel) && this.getLevel() < config.expandLevel) {\n tree.expandedMap.set(this.value, true);\n expanded = true;\n }\n if (this.children === true && config.lazy) {\n expanded = false;\n }\n if (expanded) {\n tree.expandedMap.set(this.value, true);\n } else {\n tree.expandedMap.delete(this.value);\n }\n this.expanded = expanded;\n }\n\n /**\n * 初始化节点激活状态\n * @return void\n */\n private initActived(): void {\n const { tree, actived } = this;\n if (actived && this.isActivable()) {\n tree.activedMap.set(this.value, true);\n }\n }\n\n /* ------ 节点操作 ------ */\n\n /**\n * 追加节点数据\n * @param {object | object[]} data 节点数据\n * @return void\n */\n public append(data: TypeTreeNodeData | TypeTreeNodeData[]): void {\n const list = [];\n if (!Array.isArray(data)) {\n list.push(data);\n } else {\n list.push(...data);\n }\n if (list.length <= 0) {\n return;\n }\n if (!Array.isArray(this.children)) {\n this.children = [];\n }\n const { children, tree } = this;\n list.forEach((item) => {\n let node = null;\n if (item instanceof TreeNode) {\n node = item;\n node.appendTo(this.tree, this);\n } else {\n node = new TreeNode(this.tree, item, this);\n children.push(node);\n }\n });\n tree.reflow(this);\n this.updateRelated();\n }\n\n /**\n * 将当前节点追加到某个父节点的子节点列表中\n * @param {TreeStore} tree 目标树\n * @param {TreeNode} [parent] 目标父节点\n * @param {number} [index] 预期在子节点列表中的位置\n * @return void\n */\n public appendTo(tree: TreeStore, parent?: TreeNode, index?: number): void {\n const parentNode = parent;\n let targetIndex = -1;\n if (isNumber(index)) {\n targetIndex = index;\n }\n\n const targetParents = parentNode?.getParents() || [];\n const includeCurrent = targetParents.some((pnode) => pnode === this);\n if (includeCurrent) {\n throw new Error('无法将父节点插入到子节点');\n }\n\n if (parentNode === this) {\n throw new Error('无法将节点插入到本节点');\n }\n\n if (Array.isArray(parentNode?.children)) {\n const targetPosNode = parentNode?.children[targetIndex];\n if (targetPosNode && targetPosNode === this) {\n // 无需将节点插入到原位置\n return;\n }\n }\n\n // 先要取得 siblings\n // 因为要应对节点在同一个 siblings 中变换位置的情况\n let siblings = null;\n if (parentNode instanceof TreeNode) {\n if (!Array.isArray(parentNode?.children)) {\n parentNode.children = [];\n }\n siblings = parent.children;\n } else {\n siblings = tree.children;\n }\n\n // 上面的逻辑其实已经覆盖了所有业务情况\n // 这里的逻辑报错仅用于极限兜底,防止 treeStore 被误使用\n if (!Array.isArray(siblings)) {\n throw new Error('无法插入到目标位置,可插入的节点列表不存在');\n }\n\n const prevLength = siblings.length;\n const prevIndex = this.getIndex();\n\n this.remove();\n\n if (isNumber(index)) {\n let targetIndex = index;\n if (parentNode === this.parent) {\n // 前置节点被拔出后再插入到同一个 siblings 时,会引起目标 index 的变化\n // 因此要相应的变更插入位置\n // 后置节点被拔出时,目标 index 是不变的\n const curLength = siblings.length;\n if (curLength < prevLength && prevIndex <= targetIndex) {\n targetIndex -= 1;\n }\n }\n siblings.splice(targetIndex, 0, this);\n } else {\n siblings.push(this);\n }\n\n this.parent = parentNode;\n\n // 插入节点应当继承展开状态\n // 但不要继承选中状态和高亮状态\n const nodes = this.walk();\n nodes.forEach((item) => {\n const node = item;\n node.tree = tree;\n tree.nodeMap.set(node.value, node);\n tree.privateMap.set(node[privateKey], node);\n if (node.expanded) {\n tree.expandedMap.set(node.value, true);\n }\n });\n\n const updateNodes = parentNode?.walk() || tree.children.map((item) => item.walk()).flat();\n updateNodes.forEach((node) => {\n node.update();\n node.updateChecked();\n });\n\n tree.reflow();\n }\n\n /**\n * 插入一个节点或者数据到到同级节点的目标位置\n * @param {TreeNode | object} item 要插入的节点或者数据\n * @param {number} [index] 预期在子节点列表中的位置\n * @return void\n */\n private insert(item: TypeTreeItem, index?: number): void {\n const { tree, parent } = this;\n const siblings = this.getSiblings();\n let node = null;\n if (item instanceof TreeNode) {\n node = item;\n node.appendTo(tree, parent, index);\n } else if (item) {\n node = new TreeNode(tree, item, parent);\n if (isNumber(index)) {\n siblings.splice(index, 0, node);\n }\n siblings.forEach((sibling) => {\n sibling.update();\n });\n }\n tree.reflow();\n }\n\n /**\n * 在当前节点之前插入节点\n * @param {TreeNode | object} newData 要插入的节点或者数据\n * @return void\n */\n public insertBefore(newData: TypeTreeItem): void {\n const index = this.getIndex();\n this.insert(newData, index);\n }\n\n /**\n * 在当前节点之后插入节点\n * @param {TreeNode | object} newData 要插入的节点或者数据\n * @return void\n */\n public insertAfter(newData: TypeTreeItem): void {\n const index = this.getIndex();\n this.insert(newData, index + 1);\n }\n\n /**\n * 从当前树中移除本节点\n * @return void\n */\n public remove(): void {\n const { tree } = this;\n\n const nodes = this.walk();\n const siblings = this.getSiblings();\n const index = this.getIndex();\n // 从父节点的子节点列表中移除自己\n // 但不要将自己的父节点移除,避免渲染与判断失败\n if (Array.isArray(siblings)) {\n siblings.splice(index, 1);\n }\n // 清理与树的关系,但不清理自身状态\n nodes.forEach((node) => {\n node.clean();\n });\n // 同级节点的连线状态会受到影响\n siblings.forEach((node) => {\n node.update();\n });\n // 父节点选中态会受到影响\n this.updateParents();\n tree.reflow();\n }\n\n /**\n * 清除本节点与当前树的关系\n * @return void\n */\n private clean(): void {\n const { tree, value } = this;\n tree.activedMap.delete(value);\n tree.checkedMap.delete(value);\n tree.expandedMap.delete(value);\n tree.nodeMap.delete(value);\n tree.filterMap.delete(value);\n tree.privateMap.delete(this[privateKey]);\n }\n\n /**\n * 异步加载子节点\n * @return Promise<void>\n */\n private async loadChildren(): Promise<void> {\n const config: TypeTreeStoreOptions = get(this, 'tree.config') || {};\n if (this.children === true && !this.loading) {\n if (isFunction(config.load)) {\n this.loading = true;\n this.update();\n let list = [];\n list = await config.load(this);\n this.tree.emit('load', {\n node: this,\n data: list,\n });\n this.loading = false;\n if (Array.isArray(list) && list.length > 0) {\n this.append(list);\n } else {\n this.children = false;\n }\n this.update();\n }\n }\n }\n\n /**\n * 设置节点状态\n * - 为节点设置独立于配置的 disabled 状态: set({ disabled: true })\n * - 清除独立于配置的 disabled 状态: set({ disabled: null })\n * @param {object} item 节点状态对象\n * @return void\n */\n public set(item: TreeNodeState): void {\n const { tree } = this;\n const keys = Object.keys(item);\n keys.forEach((key) => {\n // key, disabled 字段可被 tree.config.keys 定义\n if (hasOwnProperty.call(setableStatus, key) || key === 'label') {\n this[key] = item[key];\n }\n if (key === 'disabled') {\n this.setDisabled(item[key]);\n }\n });\n tree.updated(this);\n }\n\n /* ------ 节点获取 ------- */\n\n /**\n * 获取本节点的父节点\n * @return TreeNode 父节点\n */\n public getParent(): TreeNode {\n return this.parent;\n }\n\n /**\n * 获取所有父级节点\n * - 顺序为从当前到根\n * @return TreeNode[] 父级节点数组\n */\n public getParents(): TreeNode[] {\n const parents = [];\n let node = this.parent;\n while (node) {\n parents.push(node);\n node = node.parent;\n }\n return parents;\n }\n\n /**\n * 获取所有兄弟节点,包含自己在内\n * @return TreeNode[] 兄弟节点数组\n */\n public getSiblings(): TreeNode[] {\n const { parent, tree } = this;\n let list: TreeNode[] = [];\n if (parent) {\n if (Array.isArray(parent.children)) {\n list = parent.children;\n }\n } else if (tree) {\n list = tree.children;\n }\n return list;\n }\n\n /**\n * 获取当前节点的子节点\n * @param {boolean} deep 是否获取所有深层子节点\n * @return TreeNodeModel[] 子节点数组\n */\n public getChildren(deep?: boolean): boolean | TypeTreeNodeModel[] {\n let childrenModel: boolean | TypeTreeNodeModel[] = false;\n const { children } = this;\n if (Array.isArray(children)) {\n if (children.length > 0) {\n if (deep) {\n const nodes = this.walk();\n nodes.shift();\n childrenModel = nodes.map((item) => item.getModel());\n } else {\n childrenModel = children.map((item) => item.getModel());\n }\n } else {\n childrenModel = false;\n }\n } else if (isBoolean(children)) {\n childrenModel = children;\n }\n return childrenModel;\n }\n\n /**\n * 获取本节点的根节点\n * @return TreeNode 根节点\n */\n public getRoot(): TreeNode {\n const parents = this.getParents();\n return parents[parents.length - 1] || null;\n }\n\n /**\n * 获取节点在父节点的子节点列表中的位置\n * - 如果没有父节点,则获取节点在根节点列表的位置\n * @return number 节点位置序号\n */\n public getIndex(): number {\n const list = this.getSiblings();\n return list.indexOf(this);\n }\n\n /**\n * 返回路径节点\n * - 路径节点包含自己在内\n * - 节点顺序与父级节点顺序相反,从根到当前\n * @return TreeNode[] 路径节点数组\n */\n public getPath(): TreeNode[] {\n const nodes = this.getParents();\n nodes.unshift(this);\n return nodes.reverse();\n }\n\n /**\n * 获取节点所在层级\n * @return number 层级序号\n */\n public getLevel(): number {\n const parents = this.getParents();\n return parents.length;\n }\n\n /* ------ 节点状态判断 ------ */\n\n /**\n * 判断节点是否被过滤\n * @return boolean 是否被过滤方法命中\n */\n public isRest(): boolean {\n const { config, filterMap, hasFilter } = this.tree;\n\n let rest = false;\n if (hasFilter) {\n // 仅在存在过滤条件时,过滤命中才有效\n const nodeModel = this.getModel();\n rest = config.filter(nodeModel);\n }\n\n if (rest) {\n filterMap.set(this.value, true);\n } else if (filterMap.get(this.value)) {\n filterMap.delete(this.value);\n }\n\n return rest;\n }\n\n /**\n * 判断节点是否可见\n * @return boolean 是否可见\n */\n public isVisible(): boolean {\n const { nodeMap, hasFilter, config } = this.tree;\n const { allowFoldNodeOnFilter } = config;\n\n let visible = true;\n\n if (!nodeMap.get(this.value)) {\n // 节点不在当前树上,所以不可见\n return false;\n }\n\n if (hasFilter && !allowFoldNodeOnFilter) {\n // 如果存在过滤条件\n // 锁定状态和过滤命中状态,直接呈现\n visible = this.vmIsLocked || this.vmIsRest;\n return visible;\n }\n\n // 标志所有父节点展开导致的可见状态\n let expandVisible = true;\n const parents = this.getParents();\n if (parents.length > 0) {\n expandVisible = parents.every((node: TreeNode) => node.expanded);\n }\n\n if (hasFilter) {\n visible = expandVisible && (this.vmIsRest || this.vmIsLocked);\n } else {\n visible = expandVisible;\n }\n return visible;\n }\n\n /**\n * 判断节点为逻辑禁用状态,不包含过滤锁定状态\n * @return boolean 是否被禁用\n */\n public isDisabledState(): boolean {\n const { tree, parent } = this;\n const { config } = tree;\n const { disabled, disableCheck, checkStrictly } = config;\n let state = disabled || false;\n if (this.disabled) {\n // 整个树被禁用,则节点为禁用状态\n state = true;\n }\n if (!checkStrictly && parent?.isDisabledState()) {\n // 如果 checkStrictly 为 false\n // 父节点被禁用,则子节点也为禁用状态\n state = true;\n }\n if (typeof disableCheck === 'boolean') {\n if (disableCheck) {\n state = true;\n }\n } else if (typeof disableCheck === 'function') {\n // disableCheck 视为禁用节点的过滤函数\n if (disableCheck(this.getModel())) {\n state = true;\n }\n }\n return state;\n }\n\n /**\n * 判断节点是否呈现为禁用态,包含过滤锁定状态\n * @return boolean 是否被禁用\n */\n public isDisabled(): boolean {\n const { tree } = this;\n const { hasFilter, config } = tree;\n const { allowFoldNodeOnFilter } = config;\n if (hasFilter && !allowFoldNodeOnFilter && this.vmIsLocked && !this.vmIsRest) {\n // 当前树存在过滤条件,允许节点过滤后被折叠,当前节点为锁定节点,并且不是筛选后剩下的节点\n // 则该节点应当呈现禁用状态\n return true;\n }\n return this.isDisabledState();\n }\n\n /**\n * 判断节点是否能拖拽\n * @return boolean 是否能拖拽\n */\n public isDraggable(): boolean {\n let state = !!get(this, 'tree.config.draggable');\n if (typeof this.draggable === 'boolean') {\n state = this.draggable;\n }\n return state;\n }\n\n /**\n * 判断子节点是否互斥展开\n * @return boolean 子节点是否互斥展开\n */\n public isExpandMutex(): boolean {\n let state = !!get(this, 'tree.config.expandMutex');\n if (typeof this.expandMutex === 'boolean') {\n state = this.expandMutex;\n }\n return state;\n }\n\n /**\n * 节点是否可被激活\n * @return boolean 是否可被激活\n */\n public isActivable() {\n let state = !!get(this, 'tree.config.activable');\n if (typeof this.activable === 'boolean') {\n state = this.activable;\n }\n return state;\n }\n\n /**\n * 节点是否可选\n * @return boolean 是否可选\n */\n public isCheckable() {\n let state = !!get(this, 'tree.config.checkable');\n if (typeof this.checkable === 'boolean') {\n state = this.checkable;\n }\n return state;\n }\n\n /**\n * 节点是否被激活\n * @param {Map} [map] 预设激活节点 map, 用于计算节点在预期环境中的激活状态\n * @return boolean 是否被激活\n */\n public isActived(map?: Map<string, boolean>): boolean {\n const { tree, value } = this;\n const activedMap = map || tree.activedMap;\n return !!(tree.nodeMap.get(value) && activedMap.get(value));\n }\n\n /**\n * 节点是否已展开\n * @param {Map} [map] 预设展开节点 map, 用于计算节点在预期环境中的展开状态\n * @return boolean 是否已展开\n */\n public isExpanded(map?: Map<string, boolean>): boolean {\n const { tree, value, vmIsLocked } = this;\n const { hasFilter, config } = tree;\n const { allowFoldNodeOnFilter } = config;\n if (hasFilter && !allowFoldNodeOnFilter && vmIsLocked) return true;\n const expandedMap = map || tree.expandedMap;\n return !!(tree.nodeMap.get(value) && expandedMap.get(value));\n }\n\n /**\n * 节点是否被选中\n * @param {Map} [map] 预设选中节点 map, 用于计算节点在预期环境中的选中态\n * @return boolean 是否被选中\n */\n public isChecked(map?: TypeIdMap): boolean {\n const { children, tree, value } = this;\n const { checkStrictly, valueMode } = tree.config;\n // 节点不在当前树上,视为未选中\n if (!tree.nodeMap.get(value)) return false;\n // 节点不可选,视为未选中\n if (!this.isCheckable()) return false;\n const checkedMap = map || tree.checkedMap;\n // 严格模式,则已经可以判定选中状态\n if (checkStrictly) {\n return !!checkedMap.get(value);\n }\n let checked = false;\n // 在 checkedMap 中,则根据 valueMode 的值进行判断\n if (checkedMap.get(value)\n && (\n // 如果 valueMode 为 all、parentFirst,则视为选中\n valueMode !== 'onlyLeaf'\n // 如果 valueMode 为 onlyLeaf 并且当前节点是叶子节点,则视为选中\n || this.isLeaf()\n )\n ) {\n return true;\n }\n // 如果 valueMode 为 onlyLeaf 并且当前节点是父节点,则进一步判断\n if (Array.isArray(children) && children.length > 0) {\n // 子节点全部选中,则当前节点选中\n checked = children.every((node) => {\n const childIsChecked = node.isChecked(checkedMap);\n return childIsChecked;\n });\n } else {\n // 从父节点状态推断子节点状态\n // 这里再调用 isChecked 会导致死循环\n const parents = this.getParents();\n checked = parents.some((node) => checkedMap.get(node.value));\n }\n return checked;\n }\n\n /**\n * 是否为半选状态\n * @return boolean 是否为半选状态\n */\n public isIndeterminate(): boolean {\n const { children, tree, value } = this;\n const { checkStrictly } = tree.config;\n // 节点不在当前树上,视为未选中\n if (!tree.nodeMap.get(value)) return false;\n // 节点不可选,视为未选中\n if (!this.isCheckable()) return false;\n // 严格模式没有半选状态\n if (checkStrictly) return false;\n // 叶节点不存在半选状态\n if (!Array.isArray(children)) return false;\n\n let childChecked: null | boolean = null;\n const indeterminate = children.some((node: TreeNode) => {\n if (node.isIndeterminate()) {\n // 子节点有任意一个半选,则其为半选状态\n return true;\n }\n if (isNull(childChecked)) {\n childChecked = node.isChecked();\n }\n if (childChecked !== node.isChecked()) {\n // 子节点选中状态不一致,则其为半选状态\n return true;\n }\n return false;\n });\n\n return indeterminate;\n }\n\n /**\n * 是否为兄弟节点中的第一个节点\n * @return boolean 是否为第一个节点\n */\n public isFirst(): boolean {\n const siblings = this.getSiblings();\n return siblings[0] === this;\n }\n\n /**\n * 是否为兄弟节点中的最后一个节点\n * @return boolean 是否为最后一个节点\n */\n public isLast(): boolean {\n const siblings = this.getSiblings();\n return siblings[siblings.length - 1] === this;\n }\n\n /**\n * 是否为叶子节点,叶子节点没有子节点\n * @return boolean 是否为叶子节点\n */\n public isLeaf(): boolean {\n let isLeaf = false;\n if (Array.isArray(this.children)) {\n isLeaf = this.children.length <= 0;\n } else {\n isLeaf = !this.children;\n }\n return isLeaf;\n }\n\n /* ------ 节点状态切换 ------ */\n\n /**\n * 锁定节点,解锁节点\n * - 搜索过滤节点时,路径节点需要固定呈现,视其为锁定态\n * @param {boolean} lockState 锁定状态\n * @return void\n */\n public lock(lockState: boolean): void {\n this.vmIsLocked = lockState;\n this.expanded = this.isExpanded();\n this.visible = this.isVisible();\n }\n\n /**\n * 节点展开关闭后需要调用的状态检查函数\n * @return void\n */\n public afterExpanded(): void {\n this.update();\n // 节点展开时检查延迟加载的数据\n if (this.expanded && this.children === true) {\n this.loadChildren();\n }\n this.updateChildren();\n }\n\n /**\n * 切换节点展开状态\n * - 用于受控逻辑处理\n * - 仅返回预期状态值数组,不直接操作状态\n * @return string[] 当前树展开的节点值数组\n */\n public toggleExpanded(opts?: TypeSettingOptions): TreeNodeValue[] {\n return this.setExpanded(!this.isExpanded(), opts);\n }\n\n /**\n * 设置节点展开状态\n * @param {boolean} expanded 节点展开状态\n * @param {object} [opts] 操作选项\n * @param {boolean} [opts.directly=false] 是否直接操作节点状态\n * @return string[] 当前树展开的节点值数组\n */\n public setExpanded(\n expanded: boolean,\n opts?: TypeSettingOptions\n ): TreeNodeValue[] {\n const { tree } = this;\n const { config } = tree;\n const options = {\n directly: false,\n ...opts,\n };\n\n let map = tree.expandedMap;\n if (!options.directly) {\n map = new Map(tree.expandedMap);\n }\n\n // 手风琴效果,先折叠同级节点\n if (expanded) {\n // 列举需要展开的节点\n const shouldExpandNodes = [];\n // 自己一定在展开列表中\n shouldExpandNodes.push(this);\n if (config.expandParent) {\n // expandParent 为 true,则父节点都要展开\n this.getParents().forEach((node) => {\n shouldExpandNodes.push(node);\n });\n }\n shouldExpandNodes.forEach((node) => {\n let isExpandMutex = false;\n // 对于每一个节点,都需要判断是否启用手风琴效果\n if (node.parent) {\n isExpandMutex = node.parent.isExpandMutex();\n } else {\n isExpandMutex = tree?.config?.expandMutex;\n }\n if (isExpandMutex) {\n // 折叠列表中,先移除同级节点\n const siblings = node.getSiblings();\n siblings.forEach((snode) => {\n map.delete(snode.value);\n // 同级节点相关状态更新\n snode.update();\n snode.updateChildren();\n });\n }\n // 最后设置自己的折叠状态\n map.set(node.value, true);\n node.update();\n node.updateChildren();\n });\n } else {\n map.delete(this.value);\n }\n\n if (options.directly) {\n this.afterExpanded();\n }\n\n return tree.getExpanded(map);\n }\n\n /**\n * 切换节点激活状态\n * - 用于受控逻辑处理\n * - 仅返回预期状态值数组,不直接操作状态\n * @return string[] 当前树激活的节点值数组\n */\n public toggleActived(opts?: TypeSettingOptions): TreeNodeValue[] {\n return this.setActived(!this.isActived(), opts);\n }\n\n /**\n * 设置节点激活状态\n * @param {boolean} actived 节点激活状态\n * @param {object} [opts] 操作选项\n * @param {boolean} [opts.directly=false] 是否直接操作节点状态\n * @return string[] 当前树激活的节点值数组\n */\n public setActived(\n actived: boolean,\n opts?: TypeSettingOptions\n ): TreeNodeValue[] {\n const { tree } = this;\n const options = {\n // 为 true, 为 UI 操作,状态变更受 disabled 影响\n // 为 false, 为值操作, 状态变更不受 disabled 影响\n isAction: true,\n // 为 true, 直接操作节点状态\n // 为 false, 返回预期状态\n directly: false,\n ...opts,\n };\n const config = tree.config || {};\n let map = tree.activedMap;\n if (!options.directly) {\n map = new Map(tree.activedMap);\n }\n if (options.isAction && this.isDisabledState()) {\n // 对于 UI 动作,禁用时不可切换激活状态\n return tree.getActived(map);\n }\n if (this.isActivable()) {\n if (actived) {\n const prevKeys = Array.from(map.keys());\n if (!config.activeMultiple) {\n map.clear();\n }\n prevKeys.forEach((value) => {\n const node = tree.getNode(value);\n node?.update();\n });\n map.set(this.value, true);\n } else {\n map.delete(this.value);\n }\n }\n this.update();\n return tree.getActived(map);\n }\n\n /**\n * 是否存在未选中的未禁用子节点\n * @return boolean 未选中的未禁用子节点存在与否\n */\n public hasEnableUnCheckedChild(): boolean {\n const { children } = this;\n if (!Array.isArray(children) || children.length <= 0) {\n // 没有子节点\n return false;\n }\n let state = false;\n children.some((child) => {\n // 不理会禁用节点\n if (child.isDisabledState()) return false;\n // 不理会选中节点\n if (child.isChecked()) return false;\n if (child.isIndeterminate()) {\n // 为半选节点则进行递归检查\n if (child.hasEnableUnCheckedChild()) {\n state = true;\n return true;\n }\n // 都尽可能选中了,则检查之后的节点\n return false;\n }\n // 子节点为未选中状态,且非半选状态\n // 则直接返回 true\n state = true;\n return true;\n });\n return state;\n }\n\n /**\n * 切换节点选中状态\n * - 用于受控逻辑处理\n * - 仅返回预期状态值数组,不直接操作状态\n * @return string[] 当前树选中的节点值数组\n */\n public toggleChecked(opts?: TypeSettingOptions): TreeNodeValue[] {\n if (this.isIndeterminate()) {\n // 当前节点为半选情况下需要判断子节点是否尽可能全部选中\n // 存在可操作的未选中的子节点,则应当尽可能选中子节点\n // 不存在可操作的未选中的子节点,则应取消选中子节点\n const expectState = this.hasEnableUnCheckedChild();\n return this.setChecked(expectState, opts);\n }\n return this.setChecked(!this.isChecked(), opts);\n }\n\n /**\n * 设置节点选中状态\n * - 节点 UI 操作时调用这个方法\n * - 节点设置自身状态时调用这个方法\n * @param {boolean} checked 节点选中状态\n * @param {object} [opts] 操作选项\n * @param {boolean} [opts.isAction=true] 是否为 UI 动作\n * @param {boolean} [opts.directly=false] 是否直接操作节点状态\n * @return string[] 当前树选中的节点值数组\n */\n public setChecked(\n checked: boolean,\n opts?: TypeSettingOptions\n ): TreeNodeValue[] {\n const { tree } = this;\n const config = tree.config || {};\n const options: TypeSettingOptions = {\n // 为 true, 为 UI 操作,状态变更受 disabled 影响\n // 为 false, 为值操作, 状态变更不受 disabled 影响\n isAction: true,\n // 为 true, 直接操作节点状态\n // 为 false, 返回预期状态\n directly: false,\n ...opts,\n };\n let map = tree.checkedMap;\n if (!options.directly) {\n map = new Map(tree.checkedMap);\n }\n if (!this.isCheckable()) {\n // 当前节点非可选节点,则不可设置选中态\n return tree.getChecked(map);\n }\n if (options.isAction && this.isDisabledState()) {\n // 对于 UI 动作,禁用时不可切换选中态\n return tree.getChecked(map);\n }\n\n if (checked === this.isChecked()) {\n const shouldSet = this.isIndeterminate() && !this.hasEnableUnCheckedChild();\n if (!shouldSet) {\n // 值没有变更, 则选中态无变化\n return tree.getChecked(map);\n }\n }\n\n if (checked) {\n map.set(this.value, true);\n } else {\n map.delete(this.value);\n }\n\n if (config.checkStrictly) {\n // 严格模式下,选中态不扩散,仅操作节点自身\n if (options.directly) {\n // 严格模式值更新节点自身\n this.updateChecked();\n }\n } else {\n // 先向下游扩散选中态\n this.spreadChildrenChecked(checked, map, options);\n // 再计算上游选中态\n this.spreadParentChecked(checked, map, options);\n // 状态更新务必放到扩散动作之后\n // 过早的状态更新会导致后续计算出错\n if (options.directly) {\n const relatedNodes = tree.getRelatedNodes([this.value], {\n reverse: true,\n });\n relatedNodes.forEach((node) => {\n node.updateChecked();\n });\n }\n }\n\n return tree.getChecked(map);\n }\n\n // 选中态向上游扩散\n private spreadParentChecked(\n checked: boolean,\n map?: TypeIdMap,\n opts?: TypeSettingOptions\n ) {\n const options: TypeSettingOptions = {\n isAction: true,\n directly: false,\n ...opts,\n };\n\n // 碰到不可选节点,中断扩散\n if (!this.isCheckable()) return;\n\n const { children } = this;\n if (Array.isArray(children) && children.length > 0) {\n // 有子节点,则选中态由子节点选中态集合来决定\n map.delete(this.value);\n }\n\n const { parent } = this;\n if (!parent) return;\n parent.spreadParentChecked(checked, map, options);\n }\n\n // 选中态向下游扩散\n private spreadChildrenChecked(\n checked: boolean,\n map?: TypeIdMap,\n opts?: TypeSettingOptions\n ) {\n const options: TypeSettingOptions = {\n isAction: true,\n directly: false,\n ...opts,\n };\n\n // 碰到不可选节点,中断扩散\n if (!this.isCheckable()) return;\n // 对于 UI 动作操作,节点禁用,中断扩散\n if (options.isAction && this.isDisabledState()) return;\n\n const { children } = this;\n if (!Array.isArray(children)) return;\n if (children.length <= 0) return;\n // 有子节点,则选中态由子节点选中态集合来决定\n map.delete(this.value);\n children.forEach((node) => {\n // 对于 UI 动作,向下扩散时,禁用状态会阻止状态切换\n if (options.isAction && node.isDisabledState()) return;\n if (checked) {\n map.set(node.value, true);\n } else {\n map.delete(node.value);\n }\n node.spreadChildrenChecked(checked, map, options);\n });\n }\n\n /**\n * 设置节点禁用状态\n * @return void\n */\n public setDisabled(disabled: boolean) {\n this.disabled = disabled;\n this.update();\n this.updateChildren();\n }\n\n /* ------ 节点状态更新 ------ */\n\n /**\n * 更新节点当前状态,将节点放到延时更新检查队列\n * @return void\n */\n public update(): void {\n this.level = this.getLevel();\n this.vmIsFirst = this.isFirst();\n this.vmIsLast = this.isLast();\n this.vmIsLeaf = this.isLeaf();\n this.vmCheckable = this.isCheckable();\n this.vmIsRest = this.isRest();\n this.actived = this.isActived();\n this.expanded = this.isExpanded();\n this.visible = this.isVisible();\n this.tree.updated(this);\n }\n\n /**\n * 更新节点选中态\n * @return void\n */\n public updateChecked(): void {\n const { tree, value } = this;\n const { checkedMap } = tree;\n this.checked = this.isChecked();\n this.indeterminate = this.isIndeterminate();\n if (this.checked) {\n checkedMap.set(value, true);\n }\n tree.updated(this);\n }\n\n /**\n * 更新所有子节点状态\n * - 不包含自己\n * @return void\n */\n public updateChildren(): void {\n this.spreadChildren((node) => {\n if (node === this) return;\n node.update();\n node.updateChecked();\n });\n }\n\n /**\n * 更新所有父级节点状态\n * - 不包含自己\n * @return void\n */\n public updateParents(): void {\n this.spreadParents((node: TreeNode) => {\n if (node === this) return;\n node.update();\n node.updateChecked();\n });\n }\n\n /**\n * 更新上下游相关节点状态\n * - 包含自己\n * @return void\n */\n public updateRelated(): void {\n const { tree } = this;\n const relatedNodes = tree.getRelatedNodes([this.value]);\n relatedNodes.forEach((node) => {\n node.update();\n node.updateChecked();\n });\n }\n\n /* ------ 节点遍历 ------ */\n\n /**\n * 获取包含自己在内所有的子节点\n * - 包含自己\n * @return TreeNode[] 遍历结果节点数组\n */\n public walk(): TreeNode[] {\n const list: TreeNode[] = [];\n this.spreadChildren((node: TreeNode) => {\n list.push(node);\n });\n return list;\n }\n\n /**\n * 向下遍历操作\n * - 包含自己\n * @return void\n */\n private spreadChildren(fn: TypeFnOperation) {\n fn(this);\n const { children } = this;\n if (Array.isArray(children) && children.length > 0) {\n children.forEach((node) => {\n node?.spreadChildren(fn);\n });\n }\n }\n\n /**\n * 向上遍历操作\n * - 包含自己\n * @return void\n */\n private spreadParents(fn: TypeFnOperation) {\n fn(this);\n const { parent } = this;\n if (!parent) return;\n parent?.spreadParents(fn);\n }\n\n /**\n * 获取节点封装对象\n * - TreeNode 对象 => TypeTreeNodeModel 对象\n * - TypeTreeNodeModel 用于封装 treeNode 对外暴露的 api\n * - 用户仅可操作经过封装的对象,减少了对外暴露的 api,利于代码重构\n * @return TypeTreeNodeModel 节点封装对象\n */\n public getModel(): TypeTreeNodeModel {\n let { model } = this;\n if (!model) {\n model = createNodeModel(this);\n this.model = model;\n }\n return model;\n }\n}\n\nexport default TreeNode;\n"],"names":["hasOwnProperty","Object","prototype","setableStatus","expandMutex","activable","checkable","draggable","loading","setableProps","keys","syncableProps","privateKey","TreeNode","tree","data","parent","_this","_classCallCheck","_defineProperty","config","prefix","propChildren","children","propLabel","label","propValue","value","propDisabled","disabled","model","level","vmCheckable","vmIsLeaf","vmIsFirst","vmIsLast","vmIsRest","vmIsLocked","visible","actived","checked","indeterminate","expanded","expandAll","uniqueId","isNil","get","nodeMap","privateMap","log","warn","concat","set","forEach","prop","initActived","initExpanded","Array","isArray","append","lazy","loadChildren","initChecked","updateChecked","update","reflow","_createClass","key","checkedMap","checkStrictly","isNumber","expandLevel","getLevel","expandedMap","delete","isActivable","activedMap","_this2","list","push","apply","_toConsumableArray","length","item","node","appendTo","updateRelated","index","_this3","parentNode","targetIndex","targetParents","getParents","includeCurrent","some","pnode","Error","targetPosNode","siblings","prevLength","prevIndex","getIndex","remove","curLength","splice","nodes","walk","updateNodes","map","flat","insert","getSiblings","sibling","insertBefore","newData","insertAfter","clean","updateParents","filterMap","_loadChildren","_asyncToGenerator","_regeneratorRuntime","mark","_callee","wrap","_callee$","_context","prev","next","isFunction","load","sent","emit","stop","arguments","_this4","call","setDisabled","updated","getParent","parents","getChildren","deep","childrenModel","shift","getModel","isBoolean","getRoot","indexOf","getPath","unshift","reverse","isRest","_this$tree","hasFilter","rest","nodeModel","filter","isVisible","_this$tree2","allowFoldNodeOnFilter","expandVisible","every","isDisabledState","disableCheck","state","isDisabled","isDraggable","isExpandMutex","isCheckable","isActived","isExpanded","isChecked","_tree$config","valueMode","isLeaf","childIsChecked","isIndeterminate","childChecked","isNull","isFirst","isLast","lock","lockState","afterExpanded","updateChildren","toggleExpanded","opts","setExpanded","options","_objectSpread","directly","Map","shouldExpandNodes","expandParent","_tree$config2","snode","getExpanded","toggleActived","setActived","isAction","getActived","prevKeys","from","activeMultiple","clear","getNode","hasEnableUnCheckedChild","child","toggleChecked","expectState","setChecked","getChecked","shouldSet","spreadChildrenChecked","spreadParentChecked","relatedNodes","getRelatedNodes","_this5","spreadChildren","_this6","spreadParents","fn","createNodeModel"],"mappings":"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