94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
import { getCurrentInstance, markRaw, provide, shallowReactive } from 'vue'
|
|
import type {
|
|
ComponentInternalInstance,
|
|
ConcreteComponent,
|
|
InjectionKey,
|
|
VNode,
|
|
VNodeNormalizedChildren,
|
|
} from 'vue'
|
|
|
|
// TODO: uniapp 不支持 vue 直接导出的 isVNode
|
|
export function isVNode(value: any): value is VNode {
|
|
return value ? value.__v_isVNode === true : false
|
|
}
|
|
|
|
export function flattenVNodes(shouldTraverseChildren: VNodeNormalizedChildren, childName?: string) {
|
|
const result: VNode[] = []
|
|
|
|
const traverse = (children: VNodeNormalizedChildren) => {
|
|
if (!Array.isArray(children))
|
|
return
|
|
children.forEach((child) => {
|
|
if (!isVNode(child))
|
|
return
|
|
|
|
if (childName) {
|
|
if (child.type && (child.type as ConcreteComponent).name === childName) {
|
|
result.push(child)
|
|
return
|
|
}
|
|
}
|
|
else {
|
|
result.push(child)
|
|
}
|
|
|
|
if (child.component?.subTree)
|
|
traverse(child.component.subTree.children)
|
|
|
|
if (child.children)
|
|
traverse(child.children)
|
|
})
|
|
}
|
|
|
|
traverse(shouldTraverseChildren)
|
|
|
|
return result
|
|
}
|
|
|
|
export function sortChildren(
|
|
parent: ComponentInternalInstance,
|
|
internalChildren: ComponentInternalInstance[],
|
|
childName?: string,
|
|
) {
|
|
const vnodes = flattenVNodes(parent && parent.subTree && parent.subTree.children, childName)
|
|
internalChildren.sort((a, b) => {
|
|
return vnodes.indexOf(a.vnode) - vnodes.indexOf(b.vnode)
|
|
})
|
|
}
|
|
|
|
// 如果指定组件名称,则只查找此组件并且查到后结束。也就是不关心此组件下的内容,在大部分场景下节省查找消耗。
|
|
export function useProvide<ProvideValue>(key: InjectionKey<ProvideValue>, childName?: string) {
|
|
const internalChildren: ComponentInternalInstance[] = shallowReactive([])
|
|
const publicChildren = shallowReactive<any[]>([])
|
|
const parent = getCurrentInstance()!
|
|
|
|
const add = (child: ComponentInternalInstance) => {
|
|
if (!child.proxy)
|
|
return
|
|
internalChildren.push(markRaw(child))
|
|
publicChildren.push(markRaw(child.proxy))
|
|
sortChildren(parent, internalChildren, childName)
|
|
}
|
|
|
|
const remove = (child: ComponentInternalInstance) => {
|
|
if (child.proxy) {
|
|
internalChildren.splice(internalChildren.indexOf(markRaw(child)), 1)
|
|
publicChildren.splice(publicChildren.indexOf(markRaw(child.proxy)), 1)
|
|
}
|
|
}
|
|
|
|
return (value?: ProvideValue) => {
|
|
provide(key, {
|
|
add,
|
|
remove,
|
|
internalChildren,
|
|
...value,
|
|
} as any)
|
|
|
|
return {
|
|
internalChildren,
|
|
children: publicChildren,
|
|
}
|
|
}
|
|
}
|