3939</template >
4040
4141<script lang="ts" setup>
42- import { computed , defineEmits , defineProps , ref } from ' vue'
42+ import { computed , defineEmits , defineProps , ref , watch } from ' vue'
4343import LayerLines from ' ./LayerLines.vue'
4444
4545const props = defineProps ({
@@ -81,27 +81,36 @@ const emit = defineEmits(['clickRow', 'moveNode'])
8181const useCollapseMap = () => {
8282 const collapseMap = ref <Record <string , boolean >>({})
8383
84- const setCollapse = (id : string , value : boolean ) => {
84+ const setCollapse = (id : string | number , value : boolean ) => {
8585 collapseMap .value [id ] = value
8686 }
8787
88- const switchCollapse = (id : string ) => {
88+ const switchCollapse = (id : string | number ) => {
8989 collapseMap .value [id ] = ! collapseMap .value [id ]
9090 }
9191
9292 return { collapseMap , setCollapse , switchCollapse }
9393}
9494
95- const { collapseMap, switchCollapse } = useCollapseMap ()
95+ const { collapseMap, setCollapse, switchCollapse } = useCollapseMap ()
9696
97- const handleSwitchCollapse = (node ) => {
97+ interface TreeNode {
98+ id: string | number
99+ label: string
100+ parentId? : string | number
101+ level: number
102+ collapsed? : boolean
103+ rawData? : any
104+ }
105+
106+ const handleSwitchCollapse = (node : TreeNode ) => {
98107 const children = node .rawData [props .childrenKey ]
99108 if (Array .isArray (children ) && children .length > 0 ) {
100109 switchCollapse (node .id )
101110 }
102111}
103112
104- const flattenTreeData = (node , parentId , level = 0 , collapsed = false ) => {
113+ const flattenTreeData = (node : any , parentId ? : string | number , level = 0 , collapsed = false ): TreeNode [] => {
105114 const { idKey, labelKey, childrenKey } = props
106115
107116 const currentNode = {
@@ -112,7 +121,7 @@ const flattenTreeData = (node, parentId, level = 0, collapsed = false) => {
112121 collapsed ,
113122 rawData: node
114123 }
115- const result = [currentNode ]
124+ const result: TreeNode [] = [currentNode ]
116125
117126 const children = node [childrenKey ]
118127
@@ -129,18 +138,14 @@ const nodes = computed(() => {
129138 return flattenTreeData ({ [props .idKey ]: props .rootId , [props .childrenKey ]: props .data }).slice (1 )
130139})
131140
132- const nodesMap = computed (() => {
141+ const nodesMap = computed < Record < string | number , TreeNode >> (() => {
133142 return nodes .value .reduce ((result , node ) => {
134143 result [node .id ] = node
135144 return result
136- }, {})
137- })
138-
139- const filteredNodes = computed (() => {
140- return nodes .value .filter ((node ) => node .label .toLowerCase ().includes (props .filterValue .toLowerCase ()))
145+ }, {} as Record <string | number , TreeNode >)
141146})
142147
143- const getAncestorIds = (nodeId ) => {
148+ const getAncestorIds = (nodeId : string | number ) : ( string | number )[] => {
144149 const currentNode = nodesMap .value [nodeId ]
145150
146151 if (! currentNode || ! currentNode .parentId ) {
@@ -154,6 +159,43 @@ const getAncestorIds = (nodeId) => {
154159 return ancestors
155160}
156161
162+ const filteredNodes = ref <TreeNode []>([])
163+
164+ // 下面两个 watch 对应的两个重新计算 filteredNodes 的场景。场景2比场景1多了展开匹配到的节点的操作
165+
166+ // 场景1. 页面树的结构发生变化,或者有节点收起或者展开,重新计算 filteredNodes
167+ watch (nodes , (nodes ) => {
168+ filteredNodes .value = nodes .filter ((node ) => node .label .toLowerCase ().includes (props .filterValue .toLowerCase ()))
169+ })
170+
171+ // 场景2. 过滤条件发生变化,重新计算 filteredNodes,并且展开匹配到的节点
172+ watch (
173+ () => props .filterValue ,
174+ (filterValue ) => {
175+ const filtered = nodes .value .filter ((node ) => node .label .toLowerCase ().includes (filterValue .toLowerCase ()))
176+
177+ let collapseMapChanged = false
178+
179+ filtered .forEach ((node ) => {
180+ // 每个节点的祖先节点中,如果存在折叠的节点,则展开
181+ for (const id of getAncestorIds (node .id )) {
182+ if (collapseMap .value [id ]) {
183+ setCollapse (id , false )
184+ collapseMapChanged = true
185+ }
186+ }
187+ })
188+
189+ // - 如果 collapseMap 有变化,会自动重新计算 nodes,更新路径:
190+ // props.filterValue -> collapseMap -> nodes -> filteredNodes -> filteredNodesWithAncestors
191+ // - 如果 collapseMap 没有变化,则重新设置 filteredNodes,更新路径:
192+ // props.filterValue -> filteredNodes -> filteredNodesWithAncestors
193+ if (! collapseMapChanged ) {
194+ filteredNodes .value = filtered
195+ }
196+ }
197+ )
198+
157199const filteredNodesWithAncestors = computed (() => {
158200 const idSet = new Set ()
159201
@@ -174,7 +216,7 @@ const lines = {
174216}
175217
176218const layerLine = computed (() => {
177- const result = {}
219+ const result: Record < number , Record < number , number >> = {}
178220
179221 const nodes = filteredNodesWithAncestors .value
180222
@@ -193,14 +235,14 @@ const layerLine = computed(() => {
193235 return result
194236})
195237
196- const handleClickRow = (node ) => {
238+ const handleClickRow = (node : TreeNode ) => {
197239 emit (' clickRow' , node )
198240}
199241
200- const draggedNode = ref (null )
201- const hoveringNodeId = ref (null )
242+ const draggedNode = ref < TreeNode | null > (null )
243+ const hoveringNodeId = ref < string | number | null > (null )
202244
203- const handleDragStart = (event , node ) => {
245+ const handleDragStart = (_event : DragEvent , node : TreeNode ) => {
204246 if (! props .draggable ) {
205247 return
206248 }
@@ -209,12 +251,12 @@ const handleDragStart = (event, node) => {
209251}
210252
211253// dragover和dragenter事件回调函数都为handleDragOver。跨行拖动时,禁止拖拽图标可能会闪一下,所以将dragenter事件也加上回调函数
212- const handleDragOver = (event , node ) => {
254+ const handleDragOver = (event : DragEvent , node : TreeNode ) => {
213255 if (! props .draggable ) {
214256 return
215257 }
216258
217- const isDescendant = getAncestorIds (node .id ).includes (draggedNode .value .id )
259+ const isDescendant = getAncestorIds (node .id ).includes (draggedNode .value ! .id )
218260
219261 if (! isDescendant ) {
220262 // 阻止默认行为以允许放置
@@ -225,7 +267,7 @@ const handleDragOver = (event, node) => {
225267 }
226268}
227269
228- const handleDrop = (event , node ) => {
270+ const handleDrop = (event : DragEvent , node : Pick < TreeNode , ' id ' > ) => {
229271 event .preventDefault ()
230272
231273 const dragged = draggedNode .value
@@ -246,7 +288,7 @@ const handleDragEnd = () => {
246288 hoveringNodeId .value = null
247289}
248290
249- const handleContainerDragOver = (event ) => {
291+ const handleContainerDragOver = (event : DragEvent ) => {
250292 if (! props .draggable ) {
251293 return
252294 }
@@ -259,7 +301,7 @@ const handleContainerDragOver = (event) => {
259301 hoveringNodeId .value = props .rootId
260302}
261303
262- const handleContainerDragLeave = (event ) => {
304+ const handleContainerDragLeave = (event : DragEvent ) => {
263305 if (! props .draggable ) {
264306 return
265307 }
0 commit comments