Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee7548e

Browse files
author
keuby
authored
Merge pull request KNXCloud#39 from KNXCloud/fix-model
fix(vue-simulator-renderer): 修复当组件根元素 teleport 时,无法正确获取组件 dom 实例
2 parents 37598c4 + a41e658 commit ee7548e

File tree

4 files changed

+74
-7
lines changed

4 files changed

+74
-7
lines changed

packages/utils/src/check.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ export type ESModule = {
33
default: any;
44
};
55

6-
export function isNil<T>(val: T): val is NonNullable<T> {
7-
return val !== null && val !== undefined;
6+
export function isNil<T>(val: T | null | undefined): val is null | undefined {
7+
return val === null && val === undefined;
88
}
99

1010
export function isObject(val: unknown): val is Record<string, unknown> {

packages/vue-simulator-renderer/src/utils/check-node.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { isObject } from './check';
2+
13
export function isCommentNode(el: Element | Text | Comment | Node): el is Comment {
24
return el.nodeType === 8;
35
}
@@ -6,6 +8,14 @@ export function isTextNode(el: Element | Text | Comment | Node): el is Text {
68
return el.nodeType === 3;
79
}
810

11+
export function isDomNode(el: unknown): el is Element | Text {
12+
return (
13+
isObject(el) &&
14+
'nodeType' in el &&
15+
(el.nodeType === Node.ELEMENT_NODE || el.nodeType === Node.TEXT_NODE)
16+
);
17+
}
18+
919
export function isEmptyNode(el: Element | Text | Comment | Node): boolean {
1020
return isCommentNode(el) || (isTextNode(el) && el.nodeValue === '');
1121
}

packages/vue-simulator-renderer/src/utils/comp-node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class ComponentRecord {
3131
}
3232

3333
export function isVNodeHTMLElement(el: unknown): el is VNodeHTMLElement {
34-
return isObject(el) && isNil(el.__vueParentComponent);
34+
return isObject(el) && !isNil(el.__vueParentComponent);
3535
}
3636

3737
export function isCompRootHTMLElement(

packages/vue-simulator-renderer/src/utils/find-dom-nodes.ts

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import { ComponentInternalInstance } from 'vue';
1+
import { ComponentInternalInstance, VNode, isVNode } from 'vue';
22
import { ComponentInstance } from '../interface';
33
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';
56

67
export function findDOMNodes(instance: ComponentInstance) {
78
const els: (Element | Text)[] = [];
89

910
const el: Element | Text = instance.$el;
1011

1112
if (isEmptyNode(el)) {
12-
appendSiblingElement(els, instance.$, el, (node) => {
13+
const internalInstance = instance.$;
14+
appendSiblingElement(els, internalInstance, el, (node) => {
1315
return node.previousSibling;
1416
});
15-
appendSiblingElement(els, instance.$, el, (node) => {
17+
appendDescendantComponent(els, internalInstance);
18+
appendSiblingElement(els, internalInstance, el, (node) => {
1619
return node.nextSibling;
1720
});
1821
} else {
@@ -46,6 +49,60 @@ function appendSiblingElement(
4649
}
4750
}
4851

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+
49106
function isChildInstance(
50107
target: ComponentInternalInstance,
51108
source: ComponentInternalInstance | null

0 commit comments

Comments
 (0)