Skip to content

Instantly share code, notes, and snippets.

@erdesigns-eu
Last active May 13, 2024 15:04
Show Gist options
  • Save erdesigns-eu/efb8d472684cabaa3573da65b97cf9d9 to your computer and use it in GitHub Desktop.
Save erdesigns-eu/efb8d472684cabaa3573da65b97cf9d9 to your computer and use it in GitHub Desktop.
Find child components in a Vue3 component. (Alternative for Vue2 $children)
/**
* 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;
};
@erdesigns-eu
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment