Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MuGuiLin
uni-app
提交
f5ba2ed0
U
uni-app
项目概览
MuGuiLin
/
uni-app
与 Fork 源项目一致
Fork自
DCloud / uni-app
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f5ba2ed0
编写于
1月 04, 2022
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix(mp): v-for + v-for + v-if (#3145)
上级
b88cc38e
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
181 addition
and
15 deletion
+181
-15
packages/uni-mp-compiler/__tests__/scope.spec.ts
packages/uni-mp-compiler/__tests__/scope.spec.ts
+48
-0
packages/uni-mp-compiler/src/transform.ts
packages/uni-mp-compiler/src/transform.ts
+4
-0
packages/uni-mp-compiler/src/transforms/utils.ts
packages/uni-mp-compiler/src/transforms/utils.ts
+26
-12
packages/uni-mp-compiler/src/transforms/vFor.ts
packages/uni-mp-compiler/src/transforms/vFor.ts
+103
-3
未找到文件。
packages/uni-mp-compiler/__tests__/scope.spec.ts
浏览文件 @
f5ba2ed0
...
...
@@ -39,6 +39,54 @@ describe('compiler: scope', () => {
`<view wx:for="{{a}}" wx:for-item="item"><view wx:if="{{true}}" data-id="{{item.a}}"></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return true ? { a: _ctx.id } : {}; }) }
}`
)
})
test
(
'
v-for + v-for + v-if
'
,
()
=>
{
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><text v-if="s == 2">s</text></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{s.a}}" wx:for-item="r"><text wx:if="{{s.b}}">s</text></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return { a: _f(_ctx.items2, (r, k1, i1) => { return s == 2 ? {} : {}; }), b: s == 2 }; }) }
}`
)
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><text v-if="a == 2">s</text></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{b}}" wx:for-item="r"><text wx:if="{{c}}">s</text></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return {}; }), b: _f(_ctx.items2, (r, k1, i1) => { return _ctx.a == 2 ? {} : {}; }), c: _ctx.a == 2 }
}`
)
})
test
(
'
v-for + v-for + v-if + v-else-if
'
,
()
=>
{
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><text v-if="a == 2">a</text><text v-else-if="s == 3">s</text></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{s.a}}" wx:for-item="r"><text wx:if="{{b}}">a</text><text wx:elif="{{s.b}}">s</text></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return { a: _f(_ctx.items2, (r, k1, i1) => { return _ctx.a == 2 ? {} : s == 3 ? {} : {}; }), b: s == 3 }; }), b: _ctx.a == 2 }
}`
)
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><text v-if="a == 2">a</text><text v-else-if="b == 3">s</text></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{b}}" wx:for-item="r"><text wx:if="{{c}}">a</text><text wx:elif="{{d}}">s</text></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return {}; }), b: _f(_ctx.items2, (r, k1, i1) => { return _ctx.a == 2 ? {} : _ctx.b == 3 ? {} : {}; }), c: _ctx.a == 2, d: _ctx.b == 3 }
}`
)
})
test
(
'
v-for + v-for + v-for + v-if
'
,
()
=>
{
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><view v-for="t in items3"><text v-if="s == 2">s</text></view></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{b}}" wx:for-item="r"><view wx:for="{{s.a}}" wx:for-item="t"><text wx:if="{{s.b}}">s</text></view></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return { a: _f(_ctx.items3, (t, k2, i2) => { return s == 2 ? {} : {}; }), b: s == 2 }; }), b: _f(_ctx.items2, (r, k1, i1) => { return {}; }) }
}`
)
assert
(
`<view v-for="s in items1"><view v-for="r in items2"><view v-for="t in items3"><text v-if="r == 2">s</text></view></view></view>`
,
`<view wx:for="{{a}}" wx:for-item="s"><view wx:for="{{b}}" wx:for-item="r"><view wx:for="{{r.a}}" wx:for-item="t"><text wx:if="{{r.b}}">s</text></view></view></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items1, (s, k0, i0) => { return {}; }), b: _f(_ctx.items2, (r, k1, i1) => { return { a: _f(_ctx.items3, (t, k2, i2) => { return r == 2 ? {} : {}; }), b: r == 2 }; }) }
}`
)
})
...
...
packages/uni-mp-compiler/src/transform.ts
浏览文件 @
f5ba2ed0
...
...
@@ -117,6 +117,7 @@ export interface TransformContext
addIdentifiers
(
exp
:
ExpressionNode
|
string
):
void
removeIdentifiers
(
exp
:
ExpressionNode
|
string
):
void
popScope
():
CodegenScope
|
undefined
getScopeIndex
(
scope
:
CodegenScope
):
number
addVIfScope
(
initScope
:
CodegenVIfScopeInit
):
CodegenVIfScope
addVForScope
(
initScope
:
CodegenVForScopeInit
):
CodegenVForScope
cache
<
T
extends
JSChildNode
>
(
exp
:
T
,
isVNode
?:
boolean
):
CacheExpression
|
T
...
...
@@ -377,6 +378,9 @@ export function createTransformContext(
return
false
},
// methods
getScopeIndex
(
scope
:
CodegenScope
)
{
return
scopes
.
indexOf
(
scope
)
},
popScope
()
{
return
scopes
.
pop
()
},
...
...
packages/uni-mp-compiler/src/transforms/utils.ts
浏览文件 @
f5ba2ed0
...
...
@@ -107,7 +107,18 @@ export function rewriteExpression(
context
:
TransformContext
|
VueTransformContext
,
babelNode
?:
Expression
,
scope
:
CodegenScope
=
(
context
as
TransformContext
).
currentScope
,
{
property
,
ignoreLiteral
}
=
{
property
:
true
,
ignoreLiteral
:
false
}
{
property
,
ignoreLiteral
,
referencedScope
,
}:
{
property
:
boolean
ignoreLiteral
:
boolean
referencedScope
?:
CodegenScope
}
=
{
property
:
true
,
ignoreLiteral
:
false
,
}
)
{
if
(
node
.
type
===
NodeTypes
.
SIMPLE_EXPRESSION
&&
node
.
isStatic
)
{
return
node
...
...
@@ -133,24 +144,27 @@ export function rewriteExpression(
}
}
scope
=
findReferencedScope
(
babelNode
,
scope
)
const
id
=
scope
.
id
.
next
()
referencedScope
=
referencedScope
||
findReferencedScope
(
babelNode
,
scope
)
const
id
=
referencedScope
!
.
id
.
next
()
if
(
property
)
{
scope
.
properties
.
push
(
objectProperty
(
identifier
(
id
),
babelNode
!
))
referencedScope
!
.
properties
.
push
(
objectProperty
(
identifier
(
id
),
babelNode
!
))
}
// 在v-for中包含的v-if块,所有变量需要补充当前v-for value前缀
if
(
isVIfScope
(
scope
))
{
if
(
isVForScope
(
scope
.
parentScope
))
{
return
createSimpleExpression
(
scope
.
parentScope
.
valueAlias
+
'
.
'
+
id
)
// 在 v-for 中包含的 v-if 块,所有变量需要补充当前 v-for value 前缀
if
(
isVIfScope
(
referencedScope
!
))
{
if
(
isVForScope
(
referencedScope
.
parentScope
))
{
return
createSimpleExpression
(
referencedScope
.
parentScope
.
valueAlias
+
'
.
'
+
id
)
}
return
createSimpleExpression
(
id
)
}
else
if
(
isVForScope
(
scope
))
{
return
createSimpleExpression
(
s
cope
.
valueAlias
+
'
.
'
+
id
)
}
else
if
(
isVForScope
(
referencedScope
!
))
{
return
createSimpleExpression
(
referencedS
cope
.
valueAlias
+
'
.
'
+
id
)
}
return
createSimpleExpression
(
id
)
}
function
findReferencedScope
(
export
function
findReferencedScope
(
node
:
Expression
,
scope
:
CodegenScope
):
CodegenScope
{
...
...
@@ -165,7 +179,7 @@ function findReferencedScope(
return
scope
}
function
isReferencedByIds
(
node
:
Expression
,
knownIds
:
string
[])
{
export
function
isReferencedByIds
(
node
:
Expression
,
knownIds
:
string
[])
{
let
referenced
=
false
walk
(
node
as
unknown
as
BaseNode
,
{
enter
(
node
:
BaseNode
,
parent
:
BaseNode
)
{
...
...
packages/uni-mp-compiler/src/transforms/vFor.ts
浏览文件 @
f5ba2ed0
...
...
@@ -13,11 +13,14 @@ import {
isTemplateNode
,
findProp
,
ComponentNode
,
findDir
,
TemplateChildNode
,
}
from
'
@vue/compiler-core
'
import
{
parseExpr
,
parseParam
}
from
'
../ast
'
import
{
createStructuralDirectiveTransform
,
isScopedSlotVFor
,
isVForScope
,
NodeTransform
,
TransformContext
,
}
from
'
../transform
'
...
...
@@ -37,10 +40,15 @@ import {
RestElement
,
returnStatement
,
}
from
'
@babel/types
'
import
{
rewriteExpression
}
from
'
./utils
'
import
{
CodegenVForScope
}
from
'
../options
'
import
{
findReferencedScope
,
isReferencedByIds
,
rewriteExpression
,
}
from
'
./utils
'
import
{
CodegenScope
,
CodegenVForScope
}
from
'
../options
'
import
{
V_FOR
}
from
'
../runtimeHelpers
'
import
{
createVSlotCallExpression
}
from
'
./vSlot
'
import
{
isElementNode
}
from
'
@dcloudio/uni-cli-shared
'
export
type
VForOptions
=
Omit
<
ForParseResult
,
'
tagType
'
>
&
{
sourceExpr
?:
Expression
...
...
@@ -106,13 +114,36 @@ export const transformFor = createStructuralDirectiveTransform(
const
indexAlias
=
parseAlias
(
indexExpr
,
indexCode
,
'
i
'
+
scopes
.
vFor
)
// 先占位 vFor,后续更新 cloneSourceExpr 为 CallExpression
const
cloneSourceExpr
=
cloneNode
(
sourceExpr
!
,
false
)
const
sourceAliasReferencedScope
=
findReferencedScope
(
cloneSourceExpr
,
context
.
currentScope
)
// 寻找子节点中 if 指令作用域
const
vIfReferencedScope
=
findVIfReferencedScope
(
node
,
context
.
currentScope
,
context
)
// 取最近的作用域
const
referencedScope
=
vIfReferencedScope
&&
context
.
getScopeIndex
(
vIfReferencedScope
)
>
context
.
getScopeIndex
(
sourceAliasReferencedScope
)
?
vIfReferencedScope
:
sourceAliasReferencedScope
const
sourceAlias
=
rewriteExpression
(
source
,
context
,
cloneSourceExpr
,
parentScope
,
// 强制 rewrite,因为即使是字符串,数字,也要走 vFor 函数
{
property
:
true
,
ignoreLiteral
:
true
}
{
property
:
true
,
ignoreLiteral
:
true
,
referencedScope
,
}
).
content
const
sourceCode
=
`{{
${
sourceAlias
}
}}`
const
vForData
:
VForOptions
=
{
...
...
@@ -204,6 +235,75 @@ function parseAlias(
return
fallback
}
function
parseVForScope
(
currentScope
:
CodegenScope
)
{
while
(
currentScope
)
{
if
(
isVForScope
(
currentScope
)
&&
!
isScopedSlotVFor
(
currentScope
))
{
return
currentScope
}
currentScope
=
currentScope
.
parent
!
}
}
function
findVIfReferencedScope
(
node
:
ElementNode
,
currentScope
:
CodegenScope
|
null
,
context
:
TransformContext
):
CodegenVForScope
|
undefined
{
if
(
!
currentScope
)
{
return
}
const
vForScope
=
parseVForScope
(
currentScope
)
if
(
!
vForScope
)
{
return
}
if
(
!
node
.
children
.
find
((
item
)
=>
checkVIfReferenced
(
item
,
vForScope
,
context
))
)
{
return
findVIfReferencedScope
(
node
,
currentScope
.
parent
,
context
)
}
return
vForScope
}
function
checkVIfReferenced
(
node
:
TemplateChildNode
,
vForScope
:
CodegenVForScope
,
context
:
TransformContext
):
boolean
{
if
(
!
isElementNode
(
node
))
{
return
false
}
// 嵌套 for 不查找
if
(
findDir
(
node
,
'
for
'
))
{
return
false
}
const
ifDir
=
findDir
(
node
,
'
if
'
)
if
(
ifDir
)
{
return
checkDirReferenced
(
ifDir
.
exp
,
vForScope
,
context
)
}
const
elseIfDir
=
findDir
(
node
,
'
else-if
'
)
if
(
elseIfDir
)
{
return
checkDirReferenced
(
elseIfDir
.
exp
,
vForScope
,
context
)
}
return
!!
node
.
children
.
find
((
item
)
=>
checkVIfReferenced
(
item
,
vForScope
,
context
)
)
}
function
checkDirReferenced
(
node
:
ExpressionNode
|
undefined
,
vForScope
:
CodegenVForScope
,
context
:
TransformContext
)
{
if
(
node
)
{
const
babelNode
=
parseExpr
(
node
,
context
)
if
(
babelNode
&&
isReferencedByIds
(
babelNode
,
vForScope
.
locals
))
{
return
true
}
}
return
false
}
function
findVForLocals
({
value
,
key
,
index
}:
ForParseResult
)
{
const
ids
:
string
[]
=
[]
if
(
value
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录