|
1 |
| -import { ComponentInternalInstance } from 'vue'; |
| 1 | +import { ComponentInternalInstance, VNode, isVNode } from 'vue'; |
2 | 2 | import { ComponentInstance } from '../interface';
|
3 | 3 | import { isVNodeHTMLElement } from './comp-node';
|
4 |
| -import { isEmptyNode } from './check-node'; |
| 4 | +import { isDomNode, isEmptyNode } from './check-node'; |
| 5 | +import { getClientRects } from './get-client-rects'; |
5 | 6 |
|
6 | 7 | export function findDOMNodes(instance: ComponentInstance) {
|
7 | 8 | const els: (Element | Text)[] = [];
|
8 | 9 |
|
9 | 10 | const el: Element | Text = instance.$el;
|
10 | 11 |
|
11 | 12 | if (isEmptyNode(el)) {
|
12 |
| - appendSiblingElement(els, instance.$, el, (node) => { |
| 13 | + const internalInstance = instance.$; |
| 14 | + appendSiblingElement(els, internalInstance, el, (node) => { |
13 | 15 | return node.previousSibling;
|
14 | 16 | });
|
15 |
| - appendSiblingElement(els, instance.$, el, (node) => { |
| 17 | + appendDescendantComponent(els, internalInstance); |
| 18 | + appendSiblingElement(els, internalInstance, el, (node) => { |
16 | 19 | return node.nextSibling;
|
17 | 20 | });
|
18 | 21 | } else {
|
@@ -46,6 +49,60 @@ function appendSiblingElement(
|
46 | 49 | }
|
47 | 50 | }
|
48 | 51 |
|
| 52 | +function appendDescendantComponent( |
| 53 | + target: (Element | Text)[], |
| 54 | + instance: ComponentInternalInstance |
| 55 | +): boolean { |
| 56 | + const subNode = instance.subTree; |
| 57 | + const current = subNode.el as Element | Text; |
| 58 | + if (isValidElement(current)) { |
| 59 | + target.push(current); |
| 60 | + return true; |
| 61 | + } |
| 62 | + if (Array.isArray(subNode.children) && subNode.children.length > 0) { |
| 63 | + return appendDescendantChildren(target, subNode.children as VNode<Element | Text>[]); |
| 64 | + } else if (subNode.component) { |
| 65 | + return appendDescendantComponent(target, subNode.component); |
| 66 | + } |
| 67 | + return false; |
| 68 | +} |
| 69 | + |
| 70 | +function appendDescendantChildren( |
| 71 | + target: (Element | Text)[], |
| 72 | + children: VNode[] |
| 73 | +): boolean { |
| 74 | + const validElements = children.map(({ el }) => el).filter(isValidElement); |
| 75 | + if (validElements.length > 0) { |
| 76 | + target.push(...validElements); |
| 77 | + return true; |
| 78 | + } else { |
| 79 | + return ( |
| 80 | + children.length > 0 && |
| 81 | + children.some((item) => { |
| 82 | + if (Array.isArray(item.children) && item.children.length > 0) { |
| 83 | + return appendDescendantChildren( |
| 84 | + target, |
| 85 | + item.children.filter((child): child is VNode<Element | Text> => |
| 86 | + isVNode(child) |
| 87 | + ) |
| 88 | + ); |
| 89 | + } else if (item.component) { |
| 90 | + return appendDescendantComponent(target, item.component); |
| 91 | + } |
| 92 | + return false; |
| 93 | + }) |
| 94 | + ); |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +function isValidElement(el: unknown): el is Element | Text { |
| 99 | + if (el && isDomNode(el) && !isEmptyNode(el)) { |
| 100 | + const rect = getClientRects(el); |
| 101 | + return rect.some((item) => item.width || item.height); |
| 102 | + } |
| 103 | + return false; |
| 104 | +} |
| 105 | + |
49 | 106 | function isChildInstance(
|
50 | 107 | target: ComponentInternalInstance,
|
51 | 108 | source: ComponentInternalInstance | null
|
|
0 commit comments