Match-id-aad38a74387ab110540aeb594a643b1be7c42a17
This commit is contained in:
parent
a5af9c4c9e
commit
ec0f0dd2c4
|
@ -3,8 +3,9 @@ import Eye from '../svgs/Eye';
|
||||||
import Debug from '../svgs/Debug';
|
import Debug from '../svgs/Debug';
|
||||||
import Copy from '../svgs/Copy';
|
import Copy from '../svgs/Copy';
|
||||||
import Triangle from '../svgs/Triangle';
|
import Triangle from '../svgs/Triangle';
|
||||||
import { useState } from 'horizon';
|
import { useState, useEffect } from 'horizon';
|
||||||
import { IData } from './VTree';
|
import { IData } from './VTree';
|
||||||
|
import { IAttr } from '../parser/parseAttr';
|
||||||
|
|
||||||
type IComponentInfo = {
|
type IComponentInfo = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -18,13 +19,6 @@ type IComponentInfo = {
|
||||||
onClickParent: (item: IData) => void;
|
onClickParent: (item: IData) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IAttr = {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
value: string | boolean;
|
|
||||||
indentation: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function collapseAllNodes(attrs: IAttr[]) {
|
function collapseAllNodes(attrs: IAttr[]) {
|
||||||
return attrs.filter((item, index) => {
|
return attrs.filter((item, index) => {
|
||||||
const nextItem = attrs[index + 1];
|
const nextItem = attrs[index + 1];
|
||||||
|
@ -34,6 +28,9 @@ function collapseAllNodes(attrs: IAttr[]) {
|
||||||
|
|
||||||
function ComponentAttr({ name, attrs }: { name: string, attrs: IAttr[] }) {
|
function ComponentAttr({ name, attrs }: { name: string, attrs: IAttr[] }) {
|
||||||
const [collapsedNode, setCollapsedNode] = useState(collapseAllNodes(attrs));
|
const [collapsedNode, setCollapsedNode] = useState(collapseAllNodes(attrs));
|
||||||
|
useEffect(() => {
|
||||||
|
setCollapsedNode(collapseAllNodes(attrs));
|
||||||
|
}, [attrs]);
|
||||||
const handleCollapse = (item: IAttr) => {
|
const handleCollapse = (item: IAttr) => {
|
||||||
const nodes = [...collapsedNode];
|
const nodes = [...collapsedNode];
|
||||||
const i = nodes.indexOf(item);
|
const i = nodes.indexOf(item);
|
||||||
|
@ -64,7 +61,9 @@ function ComponentAttr({ name, attrs }: { name: string, attrs: IAttr[] }) {
|
||||||
<span className={styles.attrArrow}>{hasChild && <Triangle director={isCollapsed ? 'right' : 'down'} />}</span>
|
<span className={styles.attrArrow}>{hasChild && <Triangle director={isCollapsed ? 'right' : 'down'} />}</span>
|
||||||
<span className={styles.attrName}>{`${item.name}`}</span>
|
<span className={styles.attrName}>{`${item.name}`}</span>
|
||||||
{' :'}
|
{' :'}
|
||||||
<span className={styles.attrValue}>{item.value}</span>
|
{item.type === 'string' || item.type === 'number'
|
||||||
|
? <input value={item.value} className={styles.attrValue}>{item.value}</input>
|
||||||
|
: <span className={styles.attrValue}>{item.value}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
if (isCollapsed) {
|
if (isCollapsed) {
|
||||||
|
@ -106,9 +105,9 @@ export default function ComponentInfo({ name, attrs, parents, onClickParent }: I
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.componentInfoMain}>
|
<div className={styles.componentInfoMain}>
|
||||||
{context && <ComponentAttr name={'context'} attrs={context} />}
|
{context && <ComponentAttr name={'context'} attrs={context} />}
|
||||||
{props && <ComponentAttr name={'props'} attrs={props} />}
|
{props && props.length !== 0 && <ComponentAttr name={'props'} attrs={props} />}
|
||||||
{state && <ComponentAttr name={'state'} attrs={state} />}
|
{state && state.length !== 0 && <ComponentAttr name={'state'} attrs={state} />}
|
||||||
{hooks && <ComponentAttr name={'hook'} attrs={hooks} />}
|
{hooks && hooks.length !== 0 && <ComponentAttr name={'hook'} attrs={hooks} />}
|
||||||
<div className={styles.parentsInfo}>
|
<div className={styles.parentsInfo}>
|
||||||
{name && <div>
|
{name && <div>
|
||||||
parents: {
|
parents: {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
.treeItem {
|
.treeItem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
line-height: 18px;
|
line-height: 1.125rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: @select-color;
|
background-color: @select-color;
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {
|
||||||
} from './../utils/constants';
|
} from './../utils/constants';
|
||||||
import { VNode } from './../../../horizon/src/renderer/vnode/VNode';
|
import { VNode } from './../../../horizon/src/renderer/vnode/VNode';
|
||||||
import { ClassComponent } from '../../../horizon/src/renderer/vnode/VNodeTags';
|
import { ClassComponent } from '../../../horizon/src/renderer/vnode/VNodeTags';
|
||||||
import { parseAttr } from '../parser/parseAttr';
|
import { parseAttr, parseHooks } from '../parser/parseAttr';
|
||||||
|
import { FunctionComponent } from './../../../horizon/src/renderer/vnode/VNodeTags';
|
||||||
|
|
||||||
const roots = [];
|
const roots = [];
|
||||||
|
|
||||||
|
@ -56,6 +57,14 @@ function parseCompAttrs(id: number) {
|
||||||
parsedProps,
|
parsedProps,
|
||||||
parsedState,
|
parsedState,
|
||||||
});
|
});
|
||||||
|
} else if (tag === FunctionComponent) {
|
||||||
|
const { props, hooks } = vNode;
|
||||||
|
const parsedProps = parseAttr(props);
|
||||||
|
const parsedHooks = parseHooks(hooks);
|
||||||
|
postMessage(ComponentAttrs, {
|
||||||
|
parsedProps,
|
||||||
|
parsedHooks,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ if (!isDev) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reconnectTimes = 0;
|
||||||
|
|
||||||
function postMessage(type: string, data: any) {
|
function postMessage(type: string, data: any) {
|
||||||
try {
|
try {
|
||||||
connection.postMessage(packagePayload({
|
connection.postMessage(packagePayload({
|
||||||
|
@ -75,14 +77,21 @@ function postMessage(type: string, data: any) {
|
||||||
}, DevToolPanel));
|
}, DevToolPanel));
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
// 可能出现 port 关闭的场景,需要重新建立连接,增加可靠性
|
// 可能出现 port 关闭的场景,需要重新建立连接,增加可靠性
|
||||||
|
if (reconnectTimes === 20) {
|
||||||
|
reconnectTimes = 0;
|
||||||
|
console.error('reconnect failed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
reconnectTimes++;
|
||||||
|
// 重建连接
|
||||||
connection = chrome.runtime.connect({
|
connection = chrome.runtime.connect({
|
||||||
name: 'panel'
|
name: 'panel'
|
||||||
});
|
});
|
||||||
connection.postMessage(packagePayload({
|
// 重新发送初始化消息
|
||||||
type: type,
|
postMessage(InitDevToolPageConnection, chrome.devtools.inspectedWindow.tabId);
|
||||||
data: data,
|
// 初始化成功后才会重新发送消息
|
||||||
}, DevToolPanel));
|
postMessage(type, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,10 +143,11 @@ function App() {
|
||||||
}, []);
|
}, []);
|
||||||
setParsedVNodeData(allTreeData);
|
setParsedVNodeData(allTreeData);
|
||||||
} else if (type === ComponentAttrs) {
|
} else if (type === ComponentAttrs) {
|
||||||
const {parsedProps, parsedState} = data;
|
const {parsedProps, parsedState, parsedHooks} = data;
|
||||||
setComponentAttrs({
|
setComponentAttrs({
|
||||||
state: parsedProps,
|
props: parsedProps,
|
||||||
props: parsedState,
|
state: parsedState,
|
||||||
|
hooks: parsedHooks,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,79 +1,133 @@
|
||||||
import { IAttr } from "../components/ComponentInfo";
|
|
||||||
|
|
||||||
// 将状态的值解析成固定格式
|
import { Hook, Reducer, Ref } from './../../../horizon/src/renderer/hooks/HookType';
|
||||||
|
|
||||||
|
// 展示值为 string 的可编辑类型
|
||||||
|
type editableStringType = 'string' | 'number' | 'undefined' | 'null';
|
||||||
|
// 展示值为 string 的不可编辑类型
|
||||||
|
type unEditableStringType = 'function' | 'symbol' | 'object' | 'map' | 'set' | 'array'
|
||||||
|
| 'dom' // 值为 dom 元素的 ref 类型
|
||||||
|
| 'ref'; // 值为其他数据的 ref 类型
|
||||||
|
|
||||||
|
type showAsStringType = editableStringType | unEditableStringType;
|
||||||
|
|
||||||
|
|
||||||
|
export type IAttr = {
|
||||||
|
name: string;
|
||||||
|
indentation: number;
|
||||||
|
hIndex?: number; // 用于记录 hook 的 hIndex 值
|
||||||
|
} & ({
|
||||||
|
type: showAsStringType;
|
||||||
|
value: string;
|
||||||
|
} | {
|
||||||
|
type: 'boolean';
|
||||||
|
value: boolean;
|
||||||
|
})
|
||||||
|
|
||||||
|
type showType = showAsStringType | 'boolean';
|
||||||
|
|
||||||
|
const parseSubAttr = (
|
||||||
|
attr: any,
|
||||||
|
parentIndentation: number,
|
||||||
|
attrName: string,
|
||||||
|
result: IAttr[],
|
||||||
|
hIndex?: number) => {
|
||||||
|
const attrType = typeof attr;
|
||||||
|
let value: any;
|
||||||
|
let showType: showType;
|
||||||
|
let addSubState;
|
||||||
|
if (attrType === 'boolean' ||
|
||||||
|
attrType === 'number' ||
|
||||||
|
attrType === 'string' ||
|
||||||
|
attrType === 'undefined') {
|
||||||
|
value = attr;
|
||||||
|
showType = attrType;
|
||||||
|
} else if (attrType === 'function') {
|
||||||
|
const funName = attr.name;
|
||||||
|
value = `f() ${funName}{}`;
|
||||||
|
} else if (attrType === 'symbol') {
|
||||||
|
value = attr.description;
|
||||||
|
} else if (attrType === 'object') {
|
||||||
|
if (attr === null) {
|
||||||
|
showType = 'null';
|
||||||
|
} else if (attr instanceof Map) {
|
||||||
|
showType = 'map';
|
||||||
|
const size = attr.size;
|
||||||
|
value = `Map(${size})`;
|
||||||
|
addSubState = () => {
|
||||||
|
attr.forEach((value, key) => {
|
||||||
|
parseSubAttr(value, parentIndentation + 2, key, result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else if (attr instanceof Set) {
|
||||||
|
showType = 'set';
|
||||||
|
const size = attr.size;
|
||||||
|
value = `Set(${size})`;
|
||||||
|
addSubState = () => {
|
||||||
|
let i = 0;
|
||||||
|
attr.forEach((value) => {
|
||||||
|
parseSubAttr(value, parentIndentation + 2, String(i), result);
|
||||||
|
});
|
||||||
|
i++;
|
||||||
|
};
|
||||||
|
} else if (Array.isArray(attr)) {
|
||||||
|
showType = 'array';
|
||||||
|
value = `Array(${attr.length})`;
|
||||||
|
addSubState = () => {
|
||||||
|
attr.forEach((value, index) => {
|
||||||
|
parseSubAttr(value, parentIndentation + 2, String(index), result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else if (attr instanceof Element) {
|
||||||
|
showType = 'dom';
|
||||||
|
value = attr.tagName;
|
||||||
|
} else {
|
||||||
|
showType = attrType;
|
||||||
|
value = '{...}';
|
||||||
|
addSubState = () => {
|
||||||
|
Object.keys(attr).forEach((key) => {
|
||||||
|
parseSubAttr(attr[key], parentIndentation + 2, key, result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const item: IAttr = {
|
||||||
|
name: attrName,
|
||||||
|
type: showType,
|
||||||
|
value,
|
||||||
|
indentation: parentIndentation + 1,
|
||||||
|
};
|
||||||
|
if (hIndex) {
|
||||||
|
item.hIndex = hIndex;
|
||||||
|
}
|
||||||
|
result.push(item);
|
||||||
|
if (addSubState) {
|
||||||
|
addSubState();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将属性的值解析成固定格式,props 和 类组件的 state 必须是一个对象
|
||||||
export function parseAttr(rootAttr: any) {
|
export function parseAttr(rootAttr: any) {
|
||||||
const result: IAttr[] = [];
|
const result: IAttr[] = [];
|
||||||
const indentation = 0;
|
const indentation = 0;
|
||||||
const parseSubAttr = (attr: any, parentIndentation: number, attrName: string) => {
|
if (typeof rootAttr === 'object' && rootAttr !== null)
|
||||||
const stateType = typeof attr;
|
|
||||||
let value: any;
|
|
||||||
let showType;
|
|
||||||
let addSubState;
|
|
||||||
if (stateType === 'boolean' ||
|
|
||||||
stateType === 'number' ||
|
|
||||||
stateType === 'string' ||
|
|
||||||
stateType === 'undefined') {
|
|
||||||
value = attr;
|
|
||||||
showType = stateType;
|
|
||||||
} else if (stateType === 'function') {
|
|
||||||
const funName = attr.name;
|
|
||||||
value = `f() ${funName}{}`;
|
|
||||||
} else if (stateType === 'symbol') {
|
|
||||||
value = attr.description;
|
|
||||||
} else if (stateType === 'object') {
|
|
||||||
if (attr === null) {
|
|
||||||
showType = 'null';
|
|
||||||
} else if (attr instanceof Map) {
|
|
||||||
showType = 'map';
|
|
||||||
const size = attr.size;
|
|
||||||
value = `Map(${size})`;
|
|
||||||
addSubState = () => {
|
|
||||||
attr.forEach((value, key) => {
|
|
||||||
parseSubAttr(value, parentIndentation + 2, key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
} else if (attr instanceof Set) {
|
|
||||||
showType = 'set';
|
|
||||||
const size = attr.size;
|
|
||||||
value = `Set(${size})`;
|
|
||||||
addSubState = () => {
|
|
||||||
let i = 0;
|
|
||||||
attr.forEach((value) => {
|
|
||||||
parseSubAttr(value, parentIndentation + 2, String(i));
|
|
||||||
});
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
} else if (Array.isArray(attr)) {
|
|
||||||
showType = 'array';
|
|
||||||
value = `Array(${attr.length})`;
|
|
||||||
addSubState = () => {
|
|
||||||
attr.forEach((value, index) => {
|
|
||||||
parseSubAttr(value, parentIndentation + 2, String(index));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
showType = stateType;
|
|
||||||
value = '{...}';
|
|
||||||
addSubState = () => {
|
|
||||||
Object.keys(attr).forEach((key) => {
|
|
||||||
parseSubAttr(attr[key], parentIndentation + 2, key);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push({
|
|
||||||
name: attrName,
|
|
||||||
type: showType,
|
|
||||||
value,
|
|
||||||
indentation: parentIndentation + 1,
|
|
||||||
});
|
|
||||||
if (addSubState) {
|
|
||||||
addSubState();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Object.keys(rootAttr).forEach(key => {
|
Object.keys(rootAttr).forEach(key => {
|
||||||
parseSubAttr(rootAttr[key], indentation, key);
|
parseSubAttr(rootAttr[key], indentation, key, result);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseHooks(hooks: Hook<any, any>[]) {
|
||||||
|
const result: IAttr[] = [];
|
||||||
|
const indentation = 0;
|
||||||
|
hooks.forEach(hook => {
|
||||||
|
const { hIndex, state ,type } = hook;
|
||||||
|
if (type === 'useState') {
|
||||||
|
parseSubAttr((state as Reducer<any, any>).stateValue, indentation, 'state', result, hIndex);
|
||||||
|
} else if (type === 'useRef') {
|
||||||
|
parseSubAttr((state as Ref<any>).current, indentation, 'ref', result, hIndex);
|
||||||
|
} else if (type === 'useReducer') {
|
||||||
|
parseSubAttr((state as Reducer<any, any>).stateValue, indentation, 'reducer', result, hIndex);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {EffectConstant} from './EffectConstant';
|
||||||
export interface Hook<S, A> {
|
export interface Hook<S, A> {
|
||||||
state: Reducer<S, A> | Effect | Memo<S> | CallBack<S> | Ref<S>;
|
state: Reducer<S, A> | Effect | Memo<S> | CallBack<S> | Ref<S>;
|
||||||
hIndex: number;
|
hIndex: number;
|
||||||
|
type?: 'useState' | 'useRef' | 'useReducer';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Reducer<S, A> {
|
export interface Reducer<S, A> {
|
||||||
|
|
|
@ -87,6 +87,7 @@ export function useReducerForInit<S, A>(reducer, initArg, init, isUseState?: boo
|
||||||
}
|
}
|
||||||
|
|
||||||
const hook = createHook();
|
const hook = createHook();
|
||||||
|
hook.type = isUseState ? 'useState' : 'useReducer';
|
||||||
// 为hook.state赋值{状态值, 触发函数, reducer, updates更新数组, 是否是useState}
|
// 为hook.state赋值{状态值, 触发函数, reducer, updates更新数组, 是否是useState}
|
||||||
hook.state = {
|
hook.state = {
|
||||||
stateValue: stateValue,
|
stateValue: stateValue,
|
||||||
|
|
|
@ -12,6 +12,7 @@ export function useRefImpl<V>(value: V): Ref<V> {
|
||||||
if (stage === HookStage.Init) {
|
if (stage === HookStage.Init) {
|
||||||
hook = createHook();
|
hook = createHook();
|
||||||
hook.state = {current: value};
|
hook.state = {current: value};
|
||||||
|
hook.type = 'useRef';
|
||||||
} else if (stage === HookStage.Update) {
|
} else if (stage === HookStage.Update) {
|
||||||
hook = getCurrentHook();
|
hook = getCurrentHook();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue