Last active
May 13, 2024 15:04
-
-
Save erdesigns-eu/efb8d472684cabaa3573da65b97cf9d9 to your computer and use it in GitHub Desktop.
Find child components in a Vue3 component. (Alternative for Vue2 $children)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Find all Vue components that match the given matcher and return them in an array. | |
* @param parent The parent component to search. | |
* @param matcher The matcher to use. | |
* @returns An array of components that match the given matcher. | |
*/ | |
export const findVueChildComponents = (parent: any, matcher: RegExp | String | undefined) => { | |
const found: any[] = []; | |
const root = parent.$.subTree; | |
const walk = (vnode: any, callBack: Function) => { | |
if (!vnode) { | |
return; | |
} | |
if (vnode.component) { | |
const proxy = vnode.component.proxy; | |
if (proxy) { | |
callBack(vnode.component.proxy); | |
} | |
walk(vnode.component.subTree, callBack); | |
} else | |
if (vnode.shapeFlag & 16) { | |
const vnodes = vnode.children; | |
for (let i = 0; i < vnodes.length; i++) { | |
walk(vnodes[i], callBack); | |
} | |
} | |
}; | |
walk(root, (child: any) => { | |
let matches = false; | |
if (matcher instanceof RegExp) { | |
matches = matcher.test(child.$options.name); | |
} else | |
if (typeof matcher === "string") { | |
matches = (matcher === child.$options.name); | |
} else { | |
matches = true; | |
} | |
if (matches) { | |
found.push(child); | |
} | |
}); | |
return found; | |
}; | |
/** | |
* Find all Vue components that match the given matcher and return an array of objects containing the component and the slot the child component is in. | |
* @param parent The parent component to search. | |
* @param matcher The matcher to use. | |
* @param slot The slot to search. | |
* @returns An array of components that match the given matcher. | |
*/ | |
export const findVueChildComponentsEX = (parent: any, matcher?: RegExp | String | undefined, slot?: RegExp | String | undefined) => { | |
const found: any[] = []; | |
const walk = (vnode: any, slotNames: string[], callBack: (info: { component: any; slot: string }) => void) => { | |
if (!vnode) { | |
return; | |
} | |
if (vnode.component) { | |
const proxy = vnode.component.proxy; | |
if (proxy) { | |
callBack({ component: proxy, slot: slotNames[slotNames.length - 1] || "default" }); | |
} | |
walk(vnode.component.subTree, slotNames, callBack); | |
} else | |
if (vnode.shapeFlag & 16) { | |
const vnodes = vnode.children; | |
for (let i = 0; i < vnodes.length; i++) { | |
if (typeof vnodes[i].type === "symbol" && typeof vnodes[i].key === "string") { | |
const slotName = vnodes[i].key.slice(1) || "default"; | |
walk(vnodes[i], [...slotNames, slotName], callBack); | |
} else { | |
walk(vnodes[i], slotNames, callBack); | |
} | |
} | |
} else | |
if (typeof vnode.type === "symbol" && typeof vnode.key === "string") { | |
const slotName = vnode.key.slice(1) || "default"; | |
walk(vnode.children, [...slotNames, slotName], callBack); | |
} | |
}; | |
const root = parent.$.subTree; | |
walk(root, [], (childInfo) => { | |
let matchName = false; | |
let matchSlot = false; | |
if (matcher instanceof RegExp) { | |
matchName = matcher.test(childInfo.component.$options.name); | |
} else if (typeof matcher === "string") { | |
matchName = matcher === childInfo.component.$options.name; | |
} else { | |
matchName = true; | |
} | |
if (slot instanceof RegExp) { | |
matchSlot = slot.test(childInfo.slot); | |
} else if (typeof slot === "string") { | |
matchSlot = slot === childInfo.slot; | |
} else { | |
matchSlot = true; | |
} | |
if (matchName && matchSlot) { | |
if (slot) { | |
found.push(childInfo.component); | |
} else { | |
found.push(childInfo); | |
} | |
} | |
}); | |
return found; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I didnt write the initial function, i found it here: https://stackoverflow.com/questions/64154002/vue-3-how-to-get-information-about-children/71146789#71146789 and i used it and modified it to get the slots too.