diff --git a/packages/uni-mp-compiler/__tests__/mergeVirtualHostAttributes.spec.ts b/packages/uni-mp-compiler/__tests__/mergeVirtualHostAttributes.spec.ts
index 5814dea8271..da9eab9913d 100644
--- a/packages/uni-mp-compiler/__tests__/mergeVirtualHostAttributes.spec.ts
+++ b/packages/uni-mp-compiler/__tests__/mergeVirtualHostAttributes.spec.ts
@@ -18,17 +18,17 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('root node with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
@@ -36,7 +36,7 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'r1-2a9ec0b0', 'view', 'page'), d: _s(_ses(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'r1-2a9ec0b0')) }
+ const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei(_gei(_ctx, '', 'r1-2a9ec0b0'), 'view', 'page'), d: _s(_ses(_gei(_ctx, '', 'r1-2a9ec0b0'))) }
return __returned__
}`,
optionsX
@@ -45,25 +45,25 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('root node style with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _s(_ctx.style) }
+ return { a: _s(_ctx.style), b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _s(_ctx.style) }
+ return { a: _s(_ctx.style), b: _gei(_ctx, '') }
}`,
options
)
@@ -71,25 +71,25 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('root node class with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _n(_ctx.class1) }
+ return { a: _n(_ctx.class1), b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _n(_ctx.class1) }
+ return { a: _n(_ctx.class1), b: _gei(_ctx, '') }
}`,
options
)
@@ -97,41 +97,41 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('root node hidden with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.hidden }
+ return { a: _ctx.hidden, b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: !_ctx.show }
+ return { a: !_ctx.show, b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.show }
+ return { a: _ctx.show, b: _gei(_ctx, '') }
}`,
options
)
@@ -139,25 +139,25 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('root node id with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: 'id' in _ctx.$.type.props }
+ return { a: _gei(_ctx, 'id1') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.id1, b: 'id' in _ctx.$.type.props }
+ return { a: _gei(_ctx, _ctx.id1) }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: 'id' in _ctx.$.type.props }
+ return { a: _gei(_ctx, 'id1') }
}`,
options
)
@@ -165,7 +165,7 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? _ctx.id1 : _ctx.virtualHostId, 'view'), b: _s(_ses('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? _ctx.id1 : _ctx.virtualHostId)) }
+ const __returned__ = { a: _sei(_gei(_ctx, _ctx.id1), 'view'), b: _s(_ses(_gei(_ctx, _ctx.id1))) }
return __returned__
}`,
optionsX
@@ -174,7 +174,7 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId, 'view'), d: _s(_ses('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId)) }
+ const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei(_gei(_ctx, 'page'), 'view'), d: _s(_ses(_gei(_ctx, 'page'))) }
return __returned__
}`,
optionsX
@@ -183,7 +183,7 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei(('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId) !== '' ? 'id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId : 'r1-2a9ec0b0', 'view', 'page'), d: _s(_ses(('id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId) !== '' ? 'id' in _ctx.$.type.props || _ctx.virtualHostId === '' ? 'page' : _ctx.virtualHostId : 'r1-2a9ec0b0')) }
+ const __returned__ = { a: _sei('r0-2a9ec0b0', 'image', 'img'), b: _s(_ses('r0-2a9ec0b0')), c: _sei(_gei(_ctx, 'page', 'r1-2a9ec0b0'), 'view', 'page'), d: _s(_ses(_gei(_ctx, 'page', 'r1-2a9ec0b0'))) }
return __returned__
}`,
optionsX
@@ -192,57 +192,57 @@ describe('complier: options with mergeVirtualHostAttributes', () => {
test('user component attrs with mergeVirtualHostAttributes', () => {
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.show }
+ return { a: _ctx.show, b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _p({ id: 'i' }) }
+ return { a: _p({ id: 'i' }), b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.i, b: _p({ id: _ctx.i }) }
+ return { a: _ctx.i, b: _p({ id: _ctx.i }), c: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return { a: _ctx.show }
+ return { a: _ctx.show, b: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
assert(
``,
- ``,
+ ``,
`(_ctx, _cache) => {
- return {}
+ return { a: _gei(_ctx, '') }
}`,
options
)
diff --git a/packages/uni-mp-compiler/__tests__/uniElement.spec.ts b/packages/uni-mp-compiler/__tests__/uniElement.spec.ts
index 4add6a38fe8..75dfc87d582 100644
--- a/packages/uni-mp-compiler/__tests__/uniElement.spec.ts
+++ b/packages/uni-mp-compiler/__tests__/uniElement.spec.ts
@@ -25,7 +25,7 @@ describe('compiler: transform UniElement.style.setProperty', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'view', 'view'), b: _s(_ses(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'view')) }
+ const __returned__ = { a: _sei(_gei(_ctx, 'view'), 'view'), b: _s(_ses(_gei(_ctx, 'view'))) }
return __returned__
}`,
{
@@ -48,7 +48,7 @@ describe('compiler: transform UniElement.style.setProperty', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'custom', b: _p({ id: _ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'custom' }) }
+ const __returned__ = { a: _gei(_ctx, 'custom'), b: _p({ id: _gei(_ctx, 'custom') }) }
return __returned__
}`,
{
@@ -95,7 +95,7 @@ describe('compiler: transform UniElement.style.setProperty', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'view', 'view'), b: _s(_ses(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : 'view')) }
+ const __returned__ = { a: _sei(_gei(_ctx, 'view'), 'view'), b: _s(_ses(_gei(_ctx, 'view'))) }
return __returned__
}`,
{
@@ -142,7 +142,7 @@ describe('compiler: transform UniElement.style.setProperty', () => {
``,
``,
`(_ctx, _cache) => {
- const __returned__ = { a: _sei(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : _ctx.viewId, 'view'), b: _s(_ses(_ctx.virtualHostId !== '' ? _ctx.virtualHostId : _ctx.viewId)) }
+ const __returned__ = { a: _sei(_gei(_ctx, _ctx.viewId), 'view'), b: _s(_ses(_gei(_ctx, _ctx.viewId))) }
return __returned__
}`,
{
diff --git a/packages/uni-mp-compiler/src/runtimeHelpers.ts b/packages/uni-mp-compiler/src/runtimeHelpers.ts
index 44f3053186b..f7e961c2ca0 100644
--- a/packages/uni-mp-compiler/src/runtimeHelpers.ts
+++ b/packages/uni-mp-compiler/src/runtimeHelpers.ts
@@ -16,6 +16,7 @@ export const TO_DISPLAY_STRING = Symbol(`toDisplayString`)
export const WITH_MODEL_MODIFIERS = Symbol(`withModelModifiers`)
export const SET_UNI_ELEMENT_ID = Symbol(`setUniElementId`)
export const SET_UNI_ELEMENT_STYLE = Symbol(`setUniElementStyle`)
+export const GEN_UNI_ELEMENT_ID = Symbol(`genUniElementId`)
registerRuntimeHelpers({
[V_ON]: 'o',
@@ -35,4 +36,5 @@ registerRuntimeHelpers({
[STRINGIFY_JSON]: 'j',
[SET_UNI_ELEMENT_ID]: 'sei',
[SET_UNI_ELEMENT_STYLE]: 'ses',
+ [GEN_UNI_ELEMENT_ID]: 'gei',
})
diff --git a/packages/uni-mp-compiler/src/transforms/transformId.ts b/packages/uni-mp-compiler/src/transforms/transformId.ts
index 1ddb58fe9e7..25223ce460d 100644
--- a/packages/uni-mp-compiler/src/transforms/transformId.ts
+++ b/packages/uni-mp-compiler/src/transforms/transformId.ts
@@ -1,13 +1,7 @@
import {
- type BinaryExpression,
type Expression,
- type Identifier,
- binaryExpression,
- conditionalExpression,
+ callExpression,
identifier,
- isStringLiteral,
- logicalExpression,
- memberExpression,
stringLiteral,
} from '@babel/types'
import {
@@ -16,11 +10,11 @@ import {
NodeTypes,
createSimpleExpression,
} from '@vue/compiler-core'
-import { VIRTUAL_HOST_ID } from '@dcloudio/uni-shared'
import { createBindDirectiveNode } from '@dcloudio/uni-cli-shared'
import { parseExpr } from '../ast'
import { genBabelExpr } from '../codegen'
import type { TransformContext } from '../transform'
+import { GEN_UNI_ELEMENT_ID } from '../runtimeHelpers'
import { rewriteExpression } from './utils'
export function isIdBinding({ arg, exp }: DirectiveNode) {
@@ -31,11 +25,6 @@ export function findStaticIdIndex(props: (AttributeNode | DirectiveNode)[]) {
return props.findIndex((prop) => prop.name === 'id')
}
-function genVirtualHostId(isX = false) {
- const id = identifier(VIRTUAL_HOST_ID)
- return isX ? memberExpression(identifier('_ctx'), id) : id
-}
-
export function rewriteId(
index: number,
idBindingProp: DirectiveNode,
@@ -54,54 +43,26 @@ export function rewriteId(
(props[staticIdPropIndex] as AttributeNode).value!.content
)
} else if (expr) {
- idBindingExpr = isX
- ? expr
- : identifier(rewriteExpression(idBindingProp.exp!, context).content)
+ idBindingExpr =
+ isX || virtualHost
+ ? expr
+ : identifier(rewriteExpression(idBindingProp.exp!, context).content)
} else {
idBindingExpr = stringLiteral('')
}
if (virtualHost) {
- if (
- idBindingExpr &&
- !isStringLiteral(idBindingExpr, {
- value: '',
- })
- ) {
- /**
- * 组件属性中声明id属性时,id不会被绑定到element上。`'id' in _ctx.$.type.props`
- * virtualHostId存在且id不在props内时,virtualHostId绑定到element上
- * TODO class、style也有类似的问题,但是用法并不常见,暂时遗留
- */
- let idInPropsExpr: BinaryExpression | Identifier = binaryExpression(
- 'in',
- stringLiteral('id'),
- memberExpression(
- memberExpression(
- memberExpression(identifier('_ctx'), identifier('$')),
- identifier('type')
- ),
- identifier('props')
- )
- )
- if (!isX) {
- idInPropsExpr = identifier(
- rewriteExpression(
- createSimpleExpression(genBabelExpr(idInPropsExpr)),
- context
- ).content
- )
- }
- idBindingExpr = conditionalExpression(
- logicalExpression(
- '||',
- idInPropsExpr,
- binaryExpression('===', genVirtualHostId(isX), stringLiteral(''))
- ),
- idBindingExpr,
- genVirtualHostId(isX)
+ idBindingExpr = callExpression(
+ identifier(context.helperString(GEN_UNI_ELEMENT_ID)),
+ [identifier('_ctx'), idBindingExpr]
+ )
+ if (!isX) {
+ // 非uni-app-x id绑定表达式直接生成在了模板内
+ idBindingExpr = identifier(
+ rewriteExpression(
+ createSimpleExpression(genBabelExpr(idBindingExpr)),
+ context
+ ).content
)
- } else {
- idBindingExpr = genVirtualHostId(isX)
}
}
idBindingProp.exp = createSimpleExpression(genBabelExpr(idBindingExpr))
diff --git a/packages/uni-mp-compiler/src/transforms/transformUniElement.ts b/packages/uni-mp-compiler/src/transforms/transformUniElement.ts
index 670ca8fdae6..73c971d753d 100644
--- a/packages/uni-mp-compiler/src/transforms/transformUniElement.ts
+++ b/packages/uni-mp-compiler/src/transforms/transformUniElement.ts
@@ -14,7 +14,11 @@ import {
isUserComponent,
} from '@dcloudio/uni-cli-shared'
import type { TransformContext } from '../transform'
-import { SET_UNI_ELEMENT_ID, SET_UNI_ELEMENT_STYLE } from '../runtimeHelpers'
+import {
+ GEN_UNI_ELEMENT_ID,
+ SET_UNI_ELEMENT_ID,
+ SET_UNI_ELEMENT_STYLE,
+} from '../runtimeHelpers'
import {
ATTR_ELEMENT_ID,
ATTR_ELEMENT_TAG,
@@ -31,8 +35,11 @@ import { parseRefCode } from './transformRef'
import { SetUniElementIdTagType } from '@dcloudio/uni-shared'
import { isString } from '@vue/shared'
import {
+ type Expression,
binaryExpression,
conditionalExpression,
+ isCallExpression,
+ isIdentifier,
stringLiteral,
} from '@babel/types'
import { parseExpr } from '../ast'
@@ -87,7 +94,7 @@ export function rewriteId(node: ElementNode, context: TransformContext) {
const idPropIndex = node.props.indexOf(idProp)
node.props.splice(idPropIndex, 1)
if (idProp.exp) {
- const originalId = parseExpr(idProp.exp, context)!
+ let idBindingExpr = parseExpr(idProp.exp, context)! as Expression
let genId = ''
if (context.inVFor) {
// v-for 中的 ref 需要使用 v-for 的 key 作为 id
@@ -103,18 +110,26 @@ export function rewriteId(node: ElementNode, context: TransformContext) {
} else {
genId = 'r' + context.elementRefIndex++ + '-' + context.hashId
}
+
+ // TODO context.helperString能否避免调用?
+ if (
+ isCallExpression(idBindingExpr) &&
+ isIdentifier(idBindingExpr.callee) &&
+ idBindingExpr.callee.name === context.helperString(GEN_UNI_ELEMENT_ID)
+ ) {
+ // 如果调用的是genUniElementId,则直接传入自动生成的id作为第三个参数。此特性用于减小生成代码体积
+ idBindingExpr.arguments.push(stringLiteral(genId))
+ } else {
+ idBindingExpr = conditionalExpression(
+ binaryExpression('!==', idBindingExpr, stringLiteral('')),
+ idBindingExpr,
+ stringLiteral(genId)
+ )
+ }
node.props.push(
createBindDirectiveNode(
'id',
- createSimpleExpression(
- genBabelExpr(
- conditionalExpression(
- binaryExpression('!==', originalId, stringLiteral('')),
- originalId,
- stringLiteral(genId)
- )
- )
- )
+ createSimpleExpression(genBabelExpr(idBindingExpr))
)
)
}
diff --git a/packages/uni-mp-vue/src/helpers/id.ts b/packages/uni-mp-vue/src/helpers/id.ts
index 62f30c5ca93..d65dc607621 100644
--- a/packages/uni-mp-vue/src/helpers/id.ts
+++ b/packages/uni-mp-vue/src/helpers/id.ts
@@ -1,12 +1,31 @@
-import { VIRTUAL_HOST_ID } from '@dcloudio/uni-shared'
-import type { ComponentPublicInstance } from 'vue'
+function hasIdProp(_ctx: any): boolean {
+ return (
+ _ctx.$.propsOptions &&
+ _ctx.$.propsOptions[0] &&
+ 'id' in _ctx.$.propsOptions[0]
+ )
+}
-export function resolveId(id: string, ins: ComponentPublicInstance) {
- if (ins[VIRTUAL_HOST_ID] === '') {
- return id
- }
- if ('id' in ins.$.props) {
- return id
+function hasVirtualHostId(_ctx: any): boolean {
+ // #if _X_
+ return _ctx.virtualHostId !== ''
+ // #endif
+ // #if !_X_
+ return _ctx.$scope.virtualHostId !== ''
+ // #endif
+}
+
+function genIdWithVirtualHost(_ctx: any, idBinding: string): string {
+ if (!hasVirtualHostId(_ctx) || hasIdProp(_ctx)) {
+ return idBinding
}
- return ins[VIRTUAL_HOST_ID]
+ return _ctx.virtualHostId
+}
+
+export function genUniElementId(
+ _ctx: any,
+ idBinding: string,
+ genId?: string
+): string {
+ return genIdWithVirtualHost(_ctx, idBinding) || genId || ''
}
diff --git a/packages/uni-mp-vue/src/helpers/index.ts b/packages/uni-mp-vue/src/helpers/index.ts
index efd7a823f00..3216493d715 100644
--- a/packages/uni-mp-vue/src/helpers/index.ts
+++ b/packages/uni-mp-vue/src/helpers/index.ts
@@ -16,11 +16,11 @@ import { dynamicSlot } from './dynamicSlot'
import { setRef } from './ref'
import { renderProps } from './renderProps'
import { withModelModifiers } from './withModelModifiers'
-import { resolveId } from './id'
// #if _X_
import { setUniElementId, setUniElementStyle } from './uniElement'
// #endif
+import { genUniElementId } from './id'
export { setupDevtoolsPlugin } from './devtools'
@@ -54,9 +54,9 @@ export const m: typeof withModelModifiers = (
) => withModelModifiers(fn, modifiers, isComponent)
export const j = (obj: unknown) => JSON.stringify(obj)
-export const ri: typeof resolveId = resolveId
// #if _X_
export const sei = setUniElementId
export const ses = setUniElementStyle
// #endif
+export const gei = genUniElementId