forked from opentiny/tiny-engine
feat: js panel add jsx support (#253)
* feat: JS面板支持JSX语法 * fix: 画布解析JS表达式时支持JSX语法 * fix: 修复画布解析JSX表达式时会返回undefined * feat: 添加Tree和Tooltip的自定义渲染函数属性 * fix: 修改变量名
This commit is contained in:
parent
9c72525db6
commit
91ff6aed55
|
@ -34,8 +34,8 @@ const { BROADCAST_CHANNEL } = constants
|
|||
const { hyphenateRE } = utils
|
||||
const customElements = {}
|
||||
|
||||
const transformJSX = (code) =>
|
||||
transformSync(code, {
|
||||
const transformJSX = (code) => {
|
||||
const res = transformSync(code, {
|
||||
plugins: [
|
||||
[
|
||||
babelPluginJSX,
|
||||
|
@ -46,6 +46,13 @@ const transformJSX = (code) =>
|
|||
]
|
||||
]
|
||||
})
|
||||
return (res.code || '')
|
||||
.replace(/import \{.+\} from "vue";/, '')
|
||||
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
|
||||
.replace(/_?resolveComponent/g, 'h')
|
||||
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export const blockSlotDataMap = reactive({})
|
||||
|
||||
|
@ -138,7 +145,7 @@ export const newFn = (...argv) => {
|
|||
return new Fn(...argv)
|
||||
}
|
||||
|
||||
const parseExpression = (data, scope, ctx) => {
|
||||
const parseExpression = (data, scope, ctx, isJsx = false) => {
|
||||
try {
|
||||
if (data.value.indexOf('this.i18n') > -1) {
|
||||
ctx.i18n = i18nHost.global.t
|
||||
|
@ -146,12 +153,17 @@ const parseExpression = (data, scope, ctx) => {
|
|||
ctx.t = i18nHost.global.t
|
||||
}
|
||||
|
||||
return newFn('$scope', `with($scope || {}) { return ${data.value} }`).call(ctx, {
|
||||
const expression = isJsx ? transformJSX(data.value) : data.value
|
||||
return newFn('$scope', `with($scope || {}) { return ${expression} }`).call(ctx, {
|
||||
...ctx,
|
||||
...scope,
|
||||
slotScope: scope
|
||||
})
|
||||
} catch (err) {
|
||||
// 解析抛出异常,则再尝试解析 JSX 语法。如果解析 JSX 语法仍然出现错误,isJsx 变量会确保不会再次递归执行解析
|
||||
if (!isJsx) {
|
||||
return parseExpression(data, scope, ctx, true)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
@ -347,10 +359,6 @@ export const getComponent = (name) => {
|
|||
const parseJSXFunction = (data, ctx) => {
|
||||
try {
|
||||
const newValue = transformJSX(data.value)
|
||||
.code.replace(/import \{.+\} from "vue";/, '')
|
||||
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
|
||||
.replace(/_?resolveComponent/g, 'h')
|
||||
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
|
||||
const fnInfo = parseFunctionString(newValue)
|
||||
if (!fnInfo) throw Error('函数解析失败,请检查格式。示例:function fnName() { }')
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ export default {
|
|||
|
||||
watchEffect(() => {
|
||||
const { modelValue, dataType } = props
|
||||
const val = dataType ? modelValue?.value : modelValue
|
||||
const val = dataType ? modelValue?.value || '' : modelValue
|
||||
value.value = typeof val === 'string' ? val : JSON.stringify(val, null, 2)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* Copyright (c) 2023 - present TinyEngine Authors.
|
||||
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
* Copyright (c) 2023 - present TinyEngine Authors.
|
||||
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license.
|
||||
*
|
||||
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
|
||||
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
|
||||
*
|
||||
*/
|
||||
|
||||
import { parse, parseExpression } from '@babel/parser'
|
||||
import generate from '@babel/generator'
|
||||
|
@ -24,7 +24,7 @@ export const insertName = (name, content) => content.replace(METHOD_REGEXP, `fun
|
|||
|
||||
export const removeName = (content) => content.replace(METHOD_REGEXP, 'function (')
|
||||
|
||||
export const string2Ast = (string = '') => parse(string, { sourceType: 'module', plugins: ['typescript'] })
|
||||
export const string2Ast = (string = '') => parse(string, { sourceType: 'module', plugins: ['typescript', 'jsx'] })
|
||||
|
||||
export const ast2String = (ast) => generate(ast, { retainLines: true }).code
|
||||
|
||||
|
|
|
@ -10910,7 +10910,7 @@
|
|||
"zh_CN": "基础信息"
|
||||
},
|
||||
"collapse": {
|
||||
"number": 6,
|
||||
"number": 10,
|
||||
"text": {
|
||||
"zh_CN": "显示更多"
|
||||
}
|
||||
|
@ -10985,6 +10985,28 @@
|
|||
},
|
||||
"labelPosition": "left"
|
||||
},
|
||||
{
|
||||
"property": "render-content",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "渲染函数"
|
||||
}
|
||||
},
|
||||
"required": false,
|
||||
"readOnly": false,
|
||||
"disabled": false,
|
||||
"cols": 12,
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {
|
||||
"disabled": true,
|
||||
"placeholder": "请使用变量绑定来绑定函数"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "树节点的内容区的渲染函数"
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "icon-trigger-click-node",
|
||||
"label": {
|
||||
|
@ -11532,6 +11554,28 @@
|
|||
"zh_CN": "显示的内容,也可以通过 slot#content 传入 DOM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "render-content",
|
||||
"label": {
|
||||
"text": {
|
||||
"zh_CN": "渲染函数"
|
||||
}
|
||||
},
|
||||
"required": false,
|
||||
"readOnly": false,
|
||||
"disabled": false,
|
||||
"cols": 12,
|
||||
"widget": {
|
||||
"component": "MetaInput",
|
||||
"props": {
|
||||
"disabled": true,
|
||||
"placeholder": "请使用变量绑定来绑定函数"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"zh_CN": "自定义渲染函数,返回需要渲染的节点内容"
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "modelValue",
|
||||
"label": {
|
||||
|
|
Loading…
Reference in New Issue