diff --git a/libs/extension/src/injector/index.ts b/libs/extension/src/injector/index.ts index 58575844..ad8c5714 100644 --- a/libs/extension/src/injector/index.ts +++ b/libs/extension/src/injector/index.ts @@ -6,10 +6,11 @@ import { RequestComponentAttrs, ComponentAttrs, DevToolHook, - DevToolContentScript + DevToolContentScript, ModifyAttrs, ModifyHooks, ModifyState, } from '../utils/constants'; import { VNode } from '../../../horizon/src/renderer/vnode/VNode'; import { parseVNodeAttrs } from '../parser/parseAttr'; +import { Reducer } from '../../../horizon/src/renderer/hooks/HookType'; const roots = []; @@ -54,6 +55,56 @@ function parseCompAttrs(id: number) { postMessage(ComponentAttrs, parsedAttrs); } +function modifyVNodeAttrs(data) { + const {type, id, value, path} = data; + const vNode = queryVNode(id); + if (!vNode) { + console.error('Do not find match vNode, this is a bug, please report us'); + return; + } + if (type === ModifyHooks) { + const hooks = vNode.hooks; + const editHook = hooks[path[0]]; + if ((editHook.state as Reducer).trigger) { + const editState = editHook.state as Reducer; + const editValue = editState.stateValue; + const editValueType = typeof editValue; + if (editValueType === 'string') { + editState.trigger(value); + } else if (editValueType === 'number') { + const numValue = Number(value); + const targetValue = isNaN(numValue) ? value : numValue; // 如果能转为数字,转数字,不能转数字,用原值 + editState.trigger(targetValue); + } else if(editValueType === 'object') { + if (editValue === null) { + editState.trigger(value); + } else { + const newValue = {...editValue}; + // 遍历读取到直接指向需要修改值的对象 + const attrPath = path.slice(1); + let attr = newValue; + for(let i = 0; i < attrPath.length - 1; i++) { + attr = attr[attrPath[i]]; + } + // 修改对象上的值 + attr[attrPath[attrPath.length - 1]] = value; + editState.trigger(newValue); + } + } + } + } else if (type === ModifyState) { + const instance = vNode.realNode; + const oldState = instance.state || {}; + const nextState = Object.assign({}, oldState); + let accessRef = nextState; + for(let i = 0; i < path.length - 1; i++) { + accessRef = accessRef[path[i]]; + } + accessRef[path[path.length - 1]] = value; + instance.setState(nextState); + } +} + function injectHook() { if (window.__HORIZON_DEV_HOOK__) { return; @@ -79,6 +130,8 @@ function injectHook() { send(); } else if (type === RequestComponentAttrs) { parseCompAttrs(data); + } else if (type === ModifyAttrs) { + modifyVNodeAttrs(data); } } }); diff --git a/libs/extension/src/parser/parseAttr.ts b/libs/extension/src/parser/parseAttr.ts index 652593db..34f6d78e 100644 --- a/libs/extension/src/parser/parseAttr.ts +++ b/libs/extension/src/parser/parseAttr.ts @@ -127,11 +127,9 @@ export function parseHooks(hooks: Hook[]) { // 不同 hook 的 state 有不同属性,根据是否存在该属性判断 hook 类型 // 采用这种方式是因为要拿到需要的属性值,和后续触发更新,必然要感知 hook 的属性值 // 既然已经感知了属性,就不额外添加属性进行类型判断了 - if ((state as Reducer).stateValue) { + if ((state as Reducer).trigger) { if ((state as Reducer).isUseState) { parseSubAttr((state as Reducer).stateValue, indentation, 'state', result, hIndex); - } else { - parseSubAttr((state as Reducer).stateValue, indentation, 'reducer', result, hIndex); } } else if ((state as Ref).current) { parseSubAttr((state as Ref).current, indentation, 'ref', result, hIndex); @@ -162,23 +160,31 @@ export function parseVNodeAttrs(vNode: VNode) { } // 计算属性的访问顺序 -function calculateAttrAccessPath(item: IAttr, index: number, attrs: IAttr[]) { +function calculateAttrAccessPath(item: IAttr, index: number, attrs: IAttr[], isHook: boolean) { let currentIndentation = item.indentation; const path = [item.name]; + let hookRootItem: IAttr = item; for(let i = index - 1; i >= 0; i--) { const lastItem = attrs[i]; const lastIndentation = lastItem.indentation; if (lastIndentation < currentIndentation) { + hookRootItem = lastItem; path.push(lastItem.name); currentIndentation = lastIndentation; } } path.reverse(); + if (isHook) { + if (hookRootItem) { + path[0] = hookRootItem.hIndex; + } else { + console.error('There is a bug, please report'); + } + } return path; } export function buildAttrModifyData(parsedAttrsType: string, attrs: IAttr[], value, item: IAttr, index: number, id: number) { - const path = calculateAttrAccessPath(item, index, attrs); let type; if (parsedAttrsType === 'parsedProps') { type = ModifyProps; @@ -186,10 +192,10 @@ export function buildAttrModifyData(parsedAttrsType: string, attrs: IAttr[], val type = ModifyState; } else if (parsedAttrsType === 'parsedHooks') { type = ModifyHooks; - path[0] = item.hIndex; } else { return null; } + const path = calculateAttrAccessPath(item, index, attrs, parsedAttrsType === 'parsedHooks'); return { id: id, type: type,