diff --git a/packages/vue-generator/src/generator/vue/sfc/generateAttribute.js b/packages/vue-generator/src/generator/vue/sfc/generateAttribute.js index a713728e70..2004628cfd 100644 --- a/packages/vue-generator/src/generator/vue/sfc/generateAttribute.js +++ b/packages/vue-generator/src/generator/vue/sfc/generateAttribute.js @@ -377,74 +377,106 @@ export const handleTinyIconPropsHook = (schemaData, globalHooks, config) => { }) } -export const transformObjType = (obj, globalHooks, config) => { - if (!obj || typeof obj !== 'object') { - return { - res: obj - } +// 生成 watchEffect +const genStateAccessor = (value, globalHooks) => { + if (isSetter(value?.accessor) && value.accessor.setter?.value) { + globalHooks.addStatement({ + position: INSERT_POSITION.AFTER_METHODS, + value: `vue.watchEffect(wrap(${value.accessor.setter.value}))` + }) } - let resStr = [] - let shouldBindToState = false - let shouldRenderKey = !Array.isArray(obj) + if (isGetter(value?.accessor) && value.accessor.getter?.value) { + globalHooks.addStatement({ + position: INSERT_POSITION.AFTER_METHODS, + value: `vue.watchEffect(wrap(${value.accessor.getter.value}))` + }) + } +} - for (const [key, value] of Object.entries(obj)) { - let renderKey = shouldRenderKey ? `${key}: ` : '' +const transformObjValue = (renderKey, value, globalHooks, config, transformObjType) => { + const result = { shouldBindToState: false, res: null } - if (typeof value === 'string') { - resStr.push(`${renderKey}"${value.replaceAll("'", "\\'").replaceAll(/"/g, "'")}"`) + if (typeof value === 'string') { + result.res = `${renderKey}"${value.replaceAll("'", "\\'").replaceAll(/"/g, "'")}"` - continue - } + return result + } - if (typeof value !== 'object' || value === null) { - resStr.push(`${renderKey}${value}`) + if (typeof value !== 'object' || value === null) { + result.res = `${renderKey}${value}` - continue + return result + } + + if (specialTypeHandler[value?.type]) { + const specialVal = specialTypeHandler[value.type](value, globalHooks, config)?.value || '' + result.res = `${renderKey}${specialVal}` + + if (specialTypes.includes(value.type)) { + result.shouldBindToState = true } - if (specialTypeHandler[value?.type]) { - const specialVal = specialTypeHandler[value.type](value, globalHooks, config)?.value || '' - resStr.push(`${renderKey}${specialVal}`) + return result + } - if (specialTypes.includes(value.type)) { - shouldBindToState = true - } + if (hasAccessor(value?.accessor)) { + // 递归处理其他类型 + genStateAccessor(value, globalHooks) - continue - } + const { res } = transformObjValue(renderKey, value.defaultValue, globalHooks, config, transformObjType) - if (hasAccessor(value?.accessor)) { - if (typeof value.defaultValue === 'string') { - resStr.push(`${renderKey}"${value.defaultValue.replaceAll("'", "\\'").replaceAll(/"/g, "'")}"`) - } else { - const { res: tempRes, shouldBindToState: tempShouldBindToState } = - transformObjType(value.defaultValue, globalHooks, config) || {} + if (typeof res === 'string') { + result.res = res - resStr.push(`${renderKey}${tempRes}`) + return result + } else { + const { res: tempRes, shouldBindToState: tempShouldBindToState } = + transformObjType(value.defaultValue, globalHooks, config) || {} - if (tempShouldBindToState) { - shouldBindToState = true - } - } + result.res = `${renderKey}${tempRes}` - if (isSetter(value?.accessor)) { - globalHooks.addStatement({ - position: INSERT_POSITION.AFTER_METHODS, - value: `vue.watchEffect(wrap(${value.accessor.setter?.value ?? ''}))` - }) + if (tempShouldBindToState) { + result.shouldBindToState = true } + } + } - if (isGetter(value?.accessor)) { - globalHooks.addStatement({ - position: INSERT_POSITION.AFTER_METHODS, - value: `vue.watchEffect(wrap(${value.accessor.getter?.value ?? ''}))` - }) - } + return result +} + +export const transformObjType = (obj, globalHooks, config) => { + if (!obj || typeof obj !== 'object') { + return { + res: obj + } + } + + let resStr = [] + let shouldBindToState = false + let shouldRenderKey = !Array.isArray(obj) + + for (const [key, value] of Object.entries(obj)) { + let renderKey = shouldRenderKey ? `${key}: ` : '' + + const { res, shouldBindToState: tmpShouldBindToState } = transformObjValue( + renderKey, + value, + globalHooks, + config, + transformObjType + ) + + if (tmpShouldBindToState) { + shouldBindToState = true + } + if (typeof res === 'string') { + resStr.push(res) continue } + // 复杂的 object 类型,需要递归处理 const { res: tempRes, shouldBindToState: tempShouldBindToState } = transformObjType(value, globalHooks, config) || {} diff --git a/packages/vue-generator/test/testcases/sfc/accessor/expected/Accessor.vue b/packages/vue-generator/test/testcases/sfc/accessor/expected/Accessor.vue index 00ffda6f0b..fa5fc1b75e 100644 --- a/packages/vue-generator/test/testcases/sfc/accessor/expected/Accessor.vue +++ b/packages/vue-generator/test/testcases/sfc/accessor/expected/Accessor.vue @@ -16,6 +16,9 @@ const { t, lowcodeWrap, stores } = vue.inject(I18nInjectionKey).lowcode() const wrap = lowcodeWrap(props, { emit }) wrap({ stores }) +const { utils } = wrap(function () { + return this +})() const state = vue.reactive({ firstName: 'Opentiny', lastName: 'TinyEngine', @@ -26,7 +29,22 @@ const state = vue.reactive({ trueVal: true, falseVal: false, arrVal: [1, '2', { aaa: 'aaa' }, [3, 4], true, false], - objVal: { aaa: 'aaa', arr: [1, '2', true, false, 0], ccc: { bbb: 'bbb' }, d: 32432, e: '', f: null, g: false } + objVal: { aaa: 'aaa', arr: [1, '2', true, false, 0], ccc: { bbb: 'bbb' }, d: 32432, e: '', f: null, g: false }, + IconPlusSquare: utils.IconPlusSquare(), + editConfig: { + trigger: 'click', + mode: 'cell', + showStatus: true, + activeMethod: () => { + return props.isEdit + } + }, + status: vue.computed(statusData), + buttons: [ + { type: 'primary', text: '主要操作' }, + { type: 'success', text: '成功操作' }, + { type: 'danger', text: t('operation.danger') } + ] }) wrap({ state }) @@ -70,5 +88,25 @@ vue.watchEffect( this.state.objVal = `${this.state.firstName} ${this.state.lastName}` }) ) +vue.watchEffect( + wrap(function () { + this.state.IconPlusSquare = `${this.state.firstName} ${this.state.lastName}` + }) +) +vue.watchEffect( + wrap(function () { + this.state.editConfig = `${this.state.firstName} ${this.state.lastName}` + }) +) +vue.watchEffect( + wrap(function () { + this.state.status = `${this.state.firstName} ${this.state.lastName}` + }) +) +vue.watchEffect( + wrap(function () { + this.state.buttons = `${this.state.firstName} ${this.state.lastName}` + }) +) diff --git a/packages/vue-generator/test/testcases/sfc/accessor/schema.json b/packages/vue-generator/test/testcases/sfc/accessor/schema.json index 27a6c664dd..a72472ba0f 100644 --- a/packages/vue-generator/test/testcases/sfc/accessor/schema.json +++ b/packages/vue-generator/test/testcases/sfc/accessor/schema.json @@ -94,6 +94,73 @@ "value": "function() { this.state.objVal = `${this.state.firstName} ${this.state.lastName}` }" } } + }, + "IconPlusSquare": { + "defaultValue": { + "type": "JSResource", + "value": "this.utils.IconPlusSquare()" + }, + "accessor": { + "getter": { + "type": "JSFunction", + "value": "function() { this.state.IconPlusSquare = `${this.state.firstName} ${this.state.lastName}` }" + } + } + }, + "editConfig": { + "defaultValue": { + "trigger": "click", + "mode": "cell", + "showStatus": true, + "activeMethod": { + "type": "JSFunction", + "value": "function() { return this.props.isEdit }" + } + }, + "accessor": { + "getter": { + "type": "JSFunction", + "value": "function() { this.state.editConfig = `${this.state.firstName} ${this.state.lastName}` }" + } + } + }, + "status": { + "defaultValue": { + "type": "JSExpression", + "value": "this.statusData", + "computed": true + }, + "accessor": { + "getter": { + "type": "JSFunction", + "value": "function() { this.state.status = `${this.state.firstName} ${this.state.lastName}` }" + } + } + }, + "buttons": { + "defaultValue": [ + { + "type": "primary", + "text": "主要操作" + }, + { + "type": "success", + "text": "成功操作" + }, + { + "type": "danger", + "text": { + "type": "i18n", + "key": "operation.danger" + } + } + ], + "accessor": { + "getter": { + "type": "JSFunction", + "value": "function() { this.state.buttons = `${this.state.firstName} ${this.state.lastName}` }" + } + } } }, "lifeCycles": {},