| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- import {
- provide,
- reactive,
- getCurrentInstance,
- type VNode,
- type InjectionKey,
- type VNodeNormalizedChildren,
- type ComponentPublicInstance,
- type ComponentInternalInstance
- } from 'vue'
- // 小程序端不支持从vue导出的isVNode方法,参考uni-mp-vue的实现
- function isVNode(value: any): value is VNode {
- return value ? value.__v_isVNode === true : false
- }
- export function flattenVNodes(children: VNodeNormalizedChildren) {
- const result: VNode[] = []
- const traverse = (children: VNodeNormalizedChildren) => {
- if (Array.isArray(children)) {
- children.forEach((child) => {
- if (isVNode(child)) {
- result.push(child)
- if (child.component?.subTree) {
- result.push(child.component.subTree)
- traverse(child.component.subTree.children)
- }
- if (child.children) {
- traverse(child.children)
- }
- }
- })
- }
- }
- traverse(children)
- return result
- }
- const findVNodeIndex = (vnodes: VNode[], vnode: VNode) => {
- const index = vnodes.indexOf(vnode)
- if (index === -1) {
- return vnodes.findIndex((item) => vnode.key !== undefined && vnode.key !== null && item.type === vnode.type && item.key === vnode.key)
- }
- return index
- }
- // sort children instances by vnodes order
- export function sortChildren(
- parent: ComponentInternalInstance,
- publicChildren: ComponentPublicInstance[],
- internalChildren: ComponentInternalInstance[]
- ) {
- const vnodes = parent && parent.subTree && parent.subTree.children ? flattenVNodes(parent.subTree.children) : []
- internalChildren.sort((a, b) => findVNodeIndex(vnodes, a.vnode) - findVNodeIndex(vnodes, b.vnode))
- const orderedPublicChildren = internalChildren.map((item) => item.proxy!)
- publicChildren.sort((a, b) => {
- const indexA = orderedPublicChildren.indexOf(a)
- const indexB = orderedPublicChildren.indexOf(b)
- return indexA - indexB
- })
- }
- export function useChildren<
- // eslint-disable-next-line
- Child extends ComponentPublicInstance = ComponentPublicInstance<{}, any>,
- ProvideValue = never
- >(key: InjectionKey<ProvideValue>) {
- const publicChildren: Child[] = reactive([])
- const internalChildren: ComponentInternalInstance[] = reactive([])
- const parent = getCurrentInstance()!
- const linkChildren = (value?: ProvideValue) => {
- const link = (child: ComponentInternalInstance) => {
- if (child.proxy) {
- internalChildren.push(child)
- publicChildren.push(child.proxy as Child)
- sortChildren(parent, publicChildren, internalChildren)
- }
- }
- const unlink = (child: ComponentInternalInstance) => {
- const index = internalChildren.indexOf(child)
- publicChildren.splice(index, 1)
- internalChildren.splice(index, 1)
- }
- provide(
- key,
- Object.assign(
- {
- link,
- unlink,
- children: publicChildren,
- internalChildren
- },
- value
- )
- )
- }
- return {
- children: publicChildren,
- linkChildren
- }
- }
|