Skip to content

Commit 4dbddb7

Browse files
committed
feat: component highlight
1 parent ba8edb4 commit 4dbddb7

File tree

4 files changed

+87
-33
lines changed

4 files changed

+87
-33
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function isBeingDestroyed (instance) {
2+
return instance._isBeingDestroyed || instance.isUnmounted
3+
}
4+
5+
export function getAppRecord (instance) {
6+
if (instance.root) {
7+
return instance.root.__VUE_DEVTOOLS_APP_RECORD__
8+
}
9+
}
10+
11+
export function isFragment (instance) {
12+
const appRecord = getAppRecord(instance)
13+
if (appRecord) {
14+
return appRecord.types.Fragment === instance.subTree.type
15+
}
16+
}

packages/app-backend/src/highlighter.js

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { inDoc, getComponentName, getComponentDisplayName } from '@utils/util'
22
import SharedData from '@utils/shared-data'
33
import { isBrowser, target } from '@utils/env'
44
import { getInstanceName } from './index'
5+
import { isFragment } from './components'
56

67
let overlay
78
let overlayContent
@@ -79,7 +80,8 @@ export function unHighlight () {
7980
*/
8081

8182
export function getInstanceOrVnodeRect (instance) {
82-
const el = instance.$el || instance.elm
83+
const el = instance.subTree ? instance.subTree.el : instance.$el || instance.elm
84+
8385
if (!isBrowser) {
8486
// TODO: Find position from instance or a vnode (for functional components).
8587

@@ -88,13 +90,67 @@ export function getInstanceOrVnodeRect (instance) {
8890
if (!inDoc(el)) {
8991
return
9092
}
91-
if (instance._isFragment) {
92-
return getFragmentRect(instance)
93+
94+
if (isFragment(instance)) {
95+
return getFragmentRect(instance.subTree)
96+
} else if (instance._isFragment) {
97+
return getLegacyFragmentRect(instance)
9398
} else if (el.nodeType === 1) {
9499
return el.getBoundingClientRect()
95100
}
96101
}
97102

103+
function createRect () {
104+
const rect = {
105+
top: 0,
106+
bottom: 0,
107+
left: 0,
108+
right: 0,
109+
get width () { return rect.right - rect.left },
110+
get height () { return rect.bottom - rect.top }
111+
}
112+
return rect
113+
}
114+
115+
function mergeRects (a, b) {
116+
if (!a.top || b.top < a.top) {
117+
a.top = b.top
118+
}
119+
if (!a.bottom || b.bottom > a.bottom) {
120+
a.bottom = b.bottom
121+
}
122+
if (!a.left || b.left < a.left) {
123+
a.left = b.left
124+
}
125+
if (!a.right || b.right > a.right) {
126+
a.right = b.right
127+
}
128+
}
129+
130+
function getFragmentRect (vnode) {
131+
const rect = createRect()
132+
133+
for (let i = 0, l = vnode.children.length; i < l; i++) {
134+
const child = vnode.children[i]
135+
let childRect
136+
if (isFragment(child)) {
137+
childRect = getFragmentRect(child)
138+
} else if (child.el) {
139+
const el = child.el
140+
if (el.nodeType === 1 || el.getBoundingClientRect) {
141+
childRect = el.getBoundingClientRect()
142+
} else if (el.nodeType === 3 && el.data.trim()) {
143+
childRect = getTextRect(el)
144+
}
145+
}
146+
if (childRect) {
147+
mergeRects(rect, childRect)
148+
}
149+
}
150+
151+
return rect
152+
}
153+
98154
/**
99155
* Highlight a fragment instance.
100156
* Loop over its node range and determine its bounding box.
@@ -103,36 +159,20 @@ export function getInstanceOrVnodeRect (instance) {
103159
* @return {Object}
104160
*/
105161

106-
function getFragmentRect ({ _fragmentStart, _fragmentEnd }) {
107-
let top, bottom, left, right
162+
function getLegacyFragmentRect ({ _fragmentStart, _fragmentEnd }) {
163+
const rect = createRect()
108164
util().mapNodeRange(_fragmentStart, _fragmentEnd, function (node) {
109-
let rect
165+
let childRect
110166
if (node.nodeType === 1 || node.getBoundingClientRect) {
111-
rect = node.getBoundingClientRect()
167+
childRect = node.getBoundingClientRect()
112168
} else if (node.nodeType === 3 && node.data.trim()) {
113-
rect = getTextRect(node)
169+
childRect = getTextRect(node)
114170
}
115-
if (rect) {
116-
if (!top || rect.top < top) {
117-
top = rect.top
118-
}
119-
if (!bottom || rect.bottom > bottom) {
120-
bottom = rect.bottom
121-
}
122-
if (!left || rect.left < left) {
123-
left = rect.left
124-
}
125-
if (!right || rect.right > right) {
126-
right = rect.right
127-
}
171+
if (childRect) {
172+
mergeRects(rect, childRect)
128173
}
129174
})
130-
return {
131-
top,
132-
left,
133-
width: right - left,
134-
height: bottom - top
135-
}
175+
return rect
136176
}
137177

138178
let range

packages/app-backend/src/hook.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ export function installHook (target) {
9898
}
9999
})
100100

101-
hook.on('app:init', (app, version) => {
101+
hook.on('app:init', (app, version, types) => {
102102
hook.apps.push({
103103
app,
104104
version,
105+
types
105106
})
106107
})
107108

packages/app-backend/src/index.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
} from '@utils/util'
2121
import SharedData, { init as initSharedData } from '@utils/shared-data'
2222
import { isBrowser, target } from '@utils/env'
23+
import { isBeingDestroyed } from './components'
2324

2425
// hook should have been injected before this executes.
2526
const hook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__
@@ -266,6 +267,7 @@ function scan () {
266267
const id = appRecord.id = ++rootUID
267268
const instance = appRecord.app._container._vnode.component
268269
instance.__VUE_DEVTOOLS_ROOT_UID__ = id
270+
instance.__VUE_DEVTOOLS_APP_RECORD__ = appRecord
269271
rootInstances.push(instance)
270272
}
271273
}
@@ -384,11 +386,6 @@ function getInternalInstanceChildren (instance) {
384386
}
385387
return []
386388
}
387-
388-
function isBeingDestroyed (instance) {
389-
return instance._isBeingDestroyed || instance.isUnmounted
390-
}
391-
392389
/**
393390
* Check if an instance is qualified.
394391
*

0 commit comments

Comments
 (0)