Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DCloud
uni-app
提交
e54d1f76
U
uni-app
项目概览
DCloud
/
uni-app
14 天 前同步成功
通知
751
Star
38709
Fork
3642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
8
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
uni-app
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
8
Issue
8
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
e54d1f76
编写于
11月 02, 2021
作者:
fxy060608
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip(mp): v-for + scoped slot
上级
20e52bc2
变更
22
隐藏空白更改
内联
并排
Showing
22 changed file
with
307 addition
and
73 deletion
+307
-73
packages/uni-mp-alipay/__tests__/vSlot.spec.ts
packages/uni-mp-alipay/__tests__/vSlot.spec.ts
+13
-13
packages/uni-mp-baidu/__tests__/vFor.spec.ts
packages/uni-mp-baidu/__tests__/vFor.spec.ts
+2
-2
packages/uni-mp-baidu/dist/uni.compiler.js
packages/uni-mp-baidu/dist/uni.compiler.js
+2
-2
packages/uni-mp-baidu/src/compiler/transforms/vFor.ts
packages/uni-mp-baidu/src/compiler/transforms/vFor.ts
+3
-3
packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts
packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts
+1
-1
packages/uni-mp-compiler/__tests__/slot.spec.ts
packages/uni-mp-compiler/__tests__/slot.spec.ts
+11
-2
packages/uni-mp-compiler/__tests__/test.ts
packages/uni-mp-compiler/__tests__/test.ts
+44
-0
packages/uni-mp-compiler/__tests__/vSlot.spec.ts
packages/uni-mp-compiler/__tests__/vSlot.spec.ts
+13
-13
packages/uni-mp-compiler/src/ast.ts
packages/uni-mp-compiler/src/ast.ts
+1
-1
packages/uni-mp-compiler/src/index.ts
packages/uni-mp-compiler/src/index.ts
+1
-0
packages/uni-mp-compiler/src/template/codegen.ts
packages/uni-mp-compiler/src/template/codegen.ts
+21
-4
packages/uni-mp-compiler/src/transforms/transformSlot.ts
packages/uni-mp-compiler/src/transforms/transformSlot.ts
+44
-3
packages/uni-mp-compiler/src/transforms/utils.ts
packages/uni-mp-compiler/src/transforms/utils.ts
+6
-5
packages/uni-mp-compiler/src/transforms/vSlot.ts
packages/uni-mp-compiler/src/transforms/vSlot.ts
+5
-1
packages/uni-mp-toutiao/dist/uni.compiler.js
packages/uni-mp-toutiao/dist/uni.compiler.js
+46
-1
packages/uni-mp-toutiao/src/compiler/options.ts
packages/uni-mp-toutiao/src/compiler/options.ts
+1
-0
packages/uni-mp-vue/dist/vue.runtime.esm.js
packages/uni-mp-vue/dist/vue.runtime.esm.js
+13
-8
packages/uni-mp-vue/src/helpers/index.ts
packages/uni-mp-vue/src/helpers/index.ts
+2
-1
packages/uni-mp-vue/src/helpers/renderSlot.ts
packages/uni-mp-vue/src/helpers/renderSlot.ts
+7
-3
packages/uni-mp-vue/src/helpers/withScopedSlot.ts
packages/uni-mp-vue/src/helpers/withScopedSlot.ts
+19
-7
packages/uni-mp-weixin/dist/uni.api.esm.js
packages/uni-mp-weixin/dist/uni.api.esm.js
+25
-2
packages/uni-mp-weixin/src/api/shims.ts
packages/uni-mp-weixin/src/api/shims.ts
+27
-1
未找到文件。
packages/uni-mp-alipay/__tests__/vSlot.spec.ts
浏览文件 @
e54d1f76
...
...
@@ -27,9 +27,9 @@ describe('mp-alipay: transform v-slot', () => {
)
assert
(
`<unicloud-db v-slot:default="{data, loading, error, options}" collection=""><view v-if="error">{{error.message}}</view><view v-else></view></unicloud-db>`
,
`<unicloud-db slot="default" collection="" v-i="2a9ec0b0-0" onVI="__l"><
block a:for="{{a}}" a:for-item="v0" a:key="c"><view a:if="{{v0.a}}">{{v0.b}}</view><view a:else></view></block
></unicloud-db>`
,
`<unicloud-db slot="default" collection="" v-i="2a9ec0b0-0" onVI="__l"><
view a:for="{{a}}" a:for-item="v0" a:key="c" slot="{{v0.d}}"><view a:if="{{v0.a}}">{{v0.b}}</view><view a:else></view></view
></unicloud-db>`
,
`(_ctx, _cache) => {
return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: error }, error ? { b: _t(error.message) } : {}, { c: s0 }); }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: error }, error ? { b: _t(error.message) } : {}, { c: s0
, d: i0
}); }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -37,9 +37,9 @@ describe('mp-alipay: transform v-slot', () => {
test
(
'
scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view slot="default"><
block a:for="{{a}}" a:for-item="slotProps" a:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view slot="default"><
view a:for="{{a}}" a:for-item="slotProps" a:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0
, c: i0
}; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -47,9 +47,9 @@ describe('mp-alipay: transform v-slot', () => {
test
(
'
scoped slots + scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-slot:default="slotProps"><custom1><template v-slot:default="slotProps1">{{ slotProps.item }}{{ slotProps1.item }}</template></custom1></template></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view slot="default"><
block a:for="{{a}}" a:for-item="slotProps" a:key="d"><custom1 v-i="{{slotProps.c}}" onVI="__l"><view slot="default"><block a:for="{{slotProps.a}}" a:for-item="slotProps1" a:key="b">{{slotProps.b}}{{slotProps1.a}}</block></view></custom1></block
></view></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view slot="default"><
view a:for="{{a}}" a:for-item="slotProps" a:key="d" slot="{{slotProps.e}}"><custom1 v-i="{{slotProps.c}}" onVI="__l"><view slot="default"><view a:for="{{slotProps.a}}" a:for-item="slotProps1" a:key="b" slot="{{slotProps1.c}}">{{slotProps.b}}{{slotProps1.a}}</view></view></custom1></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: _w((slotProps1, s1, i1) => { return { a: _t(slotProps1.item), b: s1
}; }, { name: 'default', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), b: _t(slotProps.item), c: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0', d: s
0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w((slotProps, s0, i0) => { return { a: _w((slotProps1, s1, i1) => { return { a: _t(slotProps1.item), b: s1
, c: i1 }; }, { name: 'default', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), b: _t(slotProps.item), c: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0', d: s0, e: i
0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -57,9 +57,9 @@ describe('mp-alipay: transform v-slot', () => {
test
(
'
v-if + scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-if="ok" v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view a:if="{{a}}" slot="default"><
block a:for="{{b}}" a:for-item="slotProps" a:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom v-i="2a9ec0b0-0" onVI="__l"><view a:if="{{a}}" slot="default"><
view a:for="{{b}}" a:for-item="slotProps" a:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) } : {})
return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0
, c: i0
}; }, { name: 'default', vueId: '2a9ec0b0-0' }) } : {})
}`
)
})
...
...
@@ -67,9 +67,9 @@ describe('mp-alipay: transform v-slot', () => {
test
(
'
v-for + scoped slots
'
,
()
=>
{
assert
(
`<custom v-for="item in items"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom a:for="{{a}}" a:for-item="item" v-i="{{item.b}}" onVI="__l"><view slot="default"><
block a:for="{{item.a}}" a:for-item="slotProps" a:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom a:for="{{a}}" a:for-item="item" v-i="{{item.b}}" onVI="__l"><view slot="default"><
view a:for="{{item.a}}" a:for-item="slotProps" a:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: _t(slotProps.item), b: s1 }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: _t(slotProps.item), b: s1
, c: i1
}; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
}`
)
})
...
...
@@ -77,16 +77,16 @@ describe('mp-alipay: transform v-slot', () => {
test
(
'
v-for + v-for + scoped slots
'
,
()
=>
{
assert
(
`<view v-for="item in items"><custom v-for="item1 in item.list" :item="item1"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom></view>`
,
`<view a:for="{{a}}" a:for-item="item"><custom a:for="{{item.a}}" a:for-item="item1" item="{{item1.b}}" v-i="{{item1.c}}" onVI="__l"><view slot="default"><
block a:for="{{item1.a}}" a:for-item="slotProps" a:key="b"><view>{{slotProps.a}}</view></block
></view></custom></view>`
,
`<view a:for="{{a}}" a:for-item="item"><custom a:for="{{item.a}}" a:for-item="item1" item="{{item1.b}}" v-i="{{item1.c}}" onVI="__l"><view slot="default"><
view a:for="{{item1.a}}" a:for-item="slotProps" a:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: _t(slotProps.item), b: s2 }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: item1, c: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }; }) }; }) }
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: _t(slotProps.item), b: s2
, c: i2
}; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: item1, c: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }; }) }; }) }
}`
)
})
test
(
'
old syntax
'
,
()
=>
{
assert
(
`<template slot="left"/>`
,
`<
block
slot="left"/>`
,
`<
view
slot="left"/>`
,
`(_ctx, _cache) => {
return {}
}`
...
...
packages/uni-mp-baidu/__tests__/vFor.spec.ts
浏览文件 @
e54d1f76
...
...
@@ -4,9 +4,9 @@ describe(`mp-baidu: transform v-for`, () => {
test
(
`with key`
,
()
=>
{
assert
(
`<view v-for="item in items" :key="item.id"/>`
,
`<view s-for="a trackBy item.
id
" s-for-item="item"/>`
,
`<view s-for="a trackBy item.
a
" s-for-item="item"/>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return {}; }) }
return { a: _f(_ctx.items, (item, k0, i0) => { return {
a: item.id
}; }) }
}`
)
})
...
...
packages/uni-mp-baidu/dist/uni.compiler.js
浏览文件 @
e54d1f76
...
...
@@ -37,7 +37,7 @@ var source = {
setting
:
setting
};
const
transformFor
=
(
node
)
=>
{
const
transformFor
=
(
node
,
context
)
=>
{
if
(
!
uniMpCompiler
.
isForElementNode
(
node
))
{
return
;
}
...
...
@@ -45,7 +45,7 @@ const transformFor = (node) => {
if
(
keyProp
)
{
const
{
exp
}
=
keyProp
;
if
(
exp
)
{
const
key
=
uniMpCompiler
.
genExpr
(
exp
)
;
const
key
=
uniMpCompiler
.
rewriteExpression
(
exp
,
context
).
content
;
node
.
vFor
.
sourceCode
=
`
${
node
.
vFor
.
sourceAlias
}
trackBy
${
key
}
`
;
node
.
props
.
splice
(
node
.
props
.
indexOf
(
keyProp
),
1
);
}
...
...
packages/uni-mp-baidu/src/compiler/transforms/vFor.ts
浏览文件 @
e54d1f76
import
{
genExpr
,
findProp
,
isForElementNode
,
DirectiveNode
,
NodeTransform
,
rewriteExpression
,
}
from
'
@dcloudio/uni-mp-compiler
'
export
const
transformFor
:
NodeTransform
=
(
node
)
=>
{
export
const
transformFor
:
NodeTransform
=
(
node
,
context
)
=>
{
if
(
!
isForElementNode
(
node
))
{
return
}
...
...
@@ -14,7 +14,7 @@ export const transformFor: NodeTransform = (node) => {
if
(
keyProp
)
{
const
{
exp
}
=
keyProp
as
DirectiveNode
if
(
exp
)
{
const
key
=
genExpr
(
exp
)
const
key
=
rewriteExpression
(
exp
,
context
).
content
node
.
vFor
.
sourceCode
=
`
${
node
.
vFor
.
sourceAlias
}
trackBy
${
key
}
`
node
.
props
.
splice
(
node
.
props
.
indexOf
(
keyProp
),
1
)
}
...
...
packages/uni-mp-compiler/__tests__/scopedSlot.spec.ts
浏览文件 @
e54d1f76
...
...
@@ -4,7 +4,7 @@ describe('compiler: transform scoped slots', () => {
test
(
'
basic
'
,
()
=>
{
assert
(
`<view><slot :item="item" :index="index"/></view>`
,
`<view><slot/></view>`
,
`<view><slot
name="default"
/></view>`
,
`(_ctx, _cache) => {
return { a: _r("default", { item: _ctx.item, index: _ctx.index }) }
}`
...
...
packages/uni-mp-compiler/__tests__/slot.spec.ts
浏览文件 @
e54d1f76
...
...
@@ -40,9 +40,18 @@ describe('compiler: transform slot', () => {
test
(
'
slot with v-for
'
,
()
=>
{
assert
(
`<slot v-for="(item,index) in items" :key="index"></slot>`
,
`<slot wx:for="{{a}}" wx:for-item="item"></slot>`
,
`<slot wx:for="{{a}}" wx:for-item="item"
name="{{item.a}}"
></slot>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, index, i0) => { return { a: _r(\"default\", { key: index }) }; }) }
return { a: _f(_ctx.items, (item, index, i0) => { return { a: "default-" + i0, b: _r("default", { key: index }, i0) }; }) }
}`
)
})
test
(
'
slot with v-for + v-for
'
,
()
=>
{
assert
(
`<view v-for="(item,index) in items" :key="index"><slot v-for="(item1,index1) in item.list" :key="index1"></slot></view>`
,
`<view wx:for="{{a}}" wx:for-item="item" wx:key="b"><slot wx:for="{{item.a}}" wx:for-item="item1" name="{{item1.a}}"></slot></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, index, i0) => { return { a: _f(item.list, (item1, index1, i1) => { return { a: "default-" + i0 + '-' + i1, b: _r("default", { key: index1 }, i0 + '-' + i1) }; }), b: index }; }) }
}`
)
})
...
...
packages/uni-mp-compiler/__tests__/test.
spec.
ts
→
packages/uni-mp-compiler/__tests__/test.ts
浏览文件 @
e54d1f76
// import { inspect } from './testUtils'
import
{
compile
}
from
'
../src
'
import
{
compile
}
from
'
../src
/index
'
import
{
CompilerOptions
}
from
'
../src/options
'
import
{
miniProgram
}
from
'
./testUtils
'
...
...
@@ -21,28 +21,24 @@ function assert(
...
miniProgram
,
emitFile
({
source
})
{
console
.
log
(
source
)
// expect(source).toBe(templateCode)
return
''
},
},
...
options
,
})
// expect(res.template).toBe(templateCode)
// expect(res.code).toBe(renderCode)
// console.log(require('util').inspect(res.code, { colors: true, depth: null }))
// console.log(require('util').inspect(res, { colors: true, depth: null }))
console
.
log
(
res
.
code
)
expect
(
res
.
code
).
toBe
(
renderCode
)
if
(
res
.
code
===
renderCode
)
{
console
.
log
(
'
success
'
)
}
else
{
console
.
error
(
'
error
'
)
console
.
error
(
renderCode
)
}
}
describe
(
'
compiler
'
,
()
=>
{
test
(
'
scope
'
,
()
=>
{
assert
(
`<view :number="20" :str="'str'" :boolean="true" :null="null" :undefined="undefined"/>`
,
`<view number="{{20}}" str="{{'str'}}" boolean="{{true}}" null="{{null}}" undefined="{{undefined}}"/>`
,
`(_ctx, _cache) => {
return {}
assert
(
`<template slot="left"/>`
,
`<slot wx:for="{{a}}" wx:for-item="item"></slot>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, index, i0) => { return { a: _r(\"default\", { key: index }) }; }) }
}`
)
})
})
)
packages/uni-mp-compiler/__tests__/vSlot.spec.ts
浏览文件 @
e54d1f76
...
...
@@ -27,9 +27,9 @@ describe('compiler: transform v-slot', () => {
)
assert
(
`<unicloud-db v-slot:default="{data, loading, error, options}" collection=""><view v-if="error">{{error.message}}</view><view v-else></view></unicloud-db>`
,
`<unicloud-db v-s="{{['default']}}" slot="default" collection="" v-i="2a9ec0b0-0"><
block wx:for="{{a}}" wx:for-item="v0" wx:key="c"><view wx:if="{{v0.a}}">{{v0.b}}</view><view wx:else></view></block
></unicloud-db>`
,
`<unicloud-db v-s="{{['default']}}" slot="default" collection="" v-i="2a9ec0b0-0"><
view wx:for="{{a}}" wx:for-item="v0" wx:key="c" slot="{{v0.d}}"><view wx:if="{{v0.a}}">{{v0.b}}</view><view wx:else></view></view
></unicloud-db>`
,
`(_ctx, _cache) => {
return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: error }, error ? { b: _t(error.message) } : {}, { c: s0 }); }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w(({ data, loading, error, options }, s0, i0) => { return _e({ a: error }, error ? { b: _t(error.message) } : {}, { c: s0
, d: i0
}); }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -37,9 +37,9 @@ describe('compiler: transform v-slot', () => {
test
(
'
scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><
block wx:for="{{a}}" wx:for-item="slotProps" wx:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><
view wx:for="{{a}}" wx:for-item="slotProps" wx:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0
, c: i0
}; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -47,9 +47,9 @@ describe('compiler: transform v-slot', () => {
test
(
'
scoped slots + scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-slot:default="slotProps"><custom1><template v-slot:default="slotProps1">{{ slotProps.item }}{{ slotProps1.item }}</template></custom1></template></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><
block wx:for="{{a}}" wx:for-item="slotProps" wx:key="d"><custom1 v-s="{{['default']}}" v-i="{{slotProps.c}}"><view slot="default"><block wx:for="{{slotProps.a}}" wx:for-item="slotProps1" wx:key="b">{{slotProps.b}}{{slotProps1.a}}</block></view></custom1></block
></view></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view slot="default"><
view wx:for="{{a}}" wx:for-item="slotProps" wx:key="d" slot="{{slotProps.e}}"><custom1 v-s="{{['default']}}" v-i="{{slotProps.c}}"><view slot="default"><view wx:for="{{slotProps.a}}" wx:for-item="slotProps1" wx:key="b" slot="{{slotProps1.c}}">{{slotProps.b}}{{slotProps1.a}}</view></view></custom1></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _w((slotProps, s0, i0) => { return { a: _w((slotProps1, s1, i1) => { return { a: _t(slotProps1.item), b: s1
}; }, { name: 'default', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), b: _t(slotProps.item), c: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0', d: s
0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
return { a: _w((slotProps, s0, i0) => { return { a: _w((slotProps1, s1, i1) => { return { a: _t(slotProps1.item), b: s1
, c: i1 }; }, { name: 'default', vueId: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0' }), b: _t(slotProps.item), c: '2a9ec0b0-1' + '-' + i0 + ',' + '2a9ec0b0-0', d: s0, e: i
0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) }
}`
)
})
...
...
@@ -57,9 +57,9 @@ describe('compiler: transform v-slot', () => {
test
(
'
v-if + scoped slots
'
,
()
=>
{
assert
(
`<custom><template v-if="ok" v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view wx:if="{{a}}" slot="default"><
block wx:for="{{b}}" wx:for-item="slotProps" wx:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom v-s="{{['default']}}" v-i="2a9ec0b0-0"><view wx:if="{{a}}" slot="default"><
view wx:for="{{b}}" wx:for-item="slotProps" wx:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0 }; }, { name: 'default', vueId: '2a9ec0b0-0' }) } : {})
return _e({ a: _ctx.ok }, _ctx.ok ? { b: _w((slotProps, s0, i0) => { return { a: _t(slotProps.item), b: s0
, c: i0
}; }, { name: 'default', vueId: '2a9ec0b0-0' }) } : {})
}`
)
})
...
...
@@ -67,9 +67,9 @@ describe('compiler: transform v-slot', () => {
test
(
'
v-for + scoped slots
'
,
()
=>
{
assert
(
`<custom v-for="item in items"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`
,
`<custom wx:for="{{a}}" wx:for-item="item" v-s="{{['default']}}" v-i="{{item.b}}"><view slot="default"><
block wx:for="{{item.a}}" wx:for-item="slotProps" wx:key="b"><view>{{slotProps.a}}</view></block
></view></custom>`
,
`<custom wx:for="{{a}}" wx:for-item="item" v-s="{{['default']}}" v-i="{{item.b}}"><view slot="default"><
view wx:for="{{item.a}}" wx:for-item="slotProps" wx:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: _t(slotProps.item), b: s1 }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _w((slotProps, s1, i1) => { return { a: _t(slotProps.item), b: s1
, c: i1
}; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 }), b: '2a9ec0b0-0' + '-' + i0 }; }) }
}`
)
})
...
...
@@ -77,16 +77,16 @@ describe('compiler: transform v-slot', () => {
test
(
'
v-for + v-for + scoped slots
'
,
()
=>
{
assert
(
`<view v-for="item in items"><custom v-for="item1 in item.list" :item="item1"><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom></view>`
,
`<view wx:for="{{a}}" wx:for-item="item"><custom wx:for="{{item.a}}" wx:for-item="item1" v-s="{{['default']}}" item="{{item1.b}}" v-i="{{item1.c}}"><view slot="default"><
block wx:for="{{item1.a}}" wx:for-item="slotProps" wx:key="b"><view>{{slotProps.a}}</view></block
></view></custom></view>`
,
`<view wx:for="{{a}}" wx:for-item="item"><custom wx:for="{{item.a}}" wx:for-item="item1" v-s="{{['default']}}" item="{{item1.b}}" v-i="{{item1.c}}"><view slot="default"><
view wx:for="{{item1.a}}" wx:for-item="slotProps" wx:key="b" slot="{{slotProps.c}}"><view>{{slotProps.a}}</view></view
></view></custom></view>`
,
`(_ctx, _cache) => {
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: _t(slotProps.item), b: s2 }; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: item1, c: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }; }) }; }) }
return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _f(item.list, (item1, k1, i1) => { return { a: _w((slotProps, s2, i2) => { return { a: _t(slotProps.item), b: s2
, c: i2
}; }, { name: 'default', vueId: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }), b: item1, c: '2a9ec0b0-0' + '-' + i0 + '-' + i1 }; }) }; }) }
}`
)
})
test
(
'
old syntax
'
,
()
=>
{
assert
(
`<template slot="left"/>`
,
`<
block
slot="left"/>`
,
`<
view
slot="left"/>`
,
`(_ctx, _cache) => {
return {}
}`
...
...
packages/uni-mp-compiler/src/ast.ts
浏览文件 @
e54d1f76
...
...
@@ -98,7 +98,7 @@ export function parseExpr(
ErrorCodes
.
X_INVALID_EXPRESSION
,
node
&&
node
.
loc
,
undefined
,
e
.
message
'
\n
'
+
code
+
'
\n
'
+
e
.
message
)
)
}
...
...
packages/uni-mp-compiler/src/index.ts
浏览文件 @
e54d1f76
...
...
@@ -21,6 +21,7 @@ export type {
}
from
'
@vue/compiler-core
'
export
{
genExpr
}
from
'
./codegen
'
export
{
rewriteExpression
}
from
'
./transforms/utils
'
export
{
isForElementNode
}
from
'
./transforms/vFor
'
export
{
transformOn
}
from
'
./transforms/vOn
'
export
{
transformModel
}
from
'
./transforms/vModel
'
...
...
packages/uni-mp-compiler/src/template/codegen.ts
浏览文件 @
e54d1f76
...
...
@@ -123,7 +123,13 @@ function genVFor(
function
genSlot
(
node
:
SlotOutletNode
,
context
:
TemplateCodegenContext
)
{
// 移除掉所有非name属性,即移除作用域插槽的绑定指令
node
.
props
=
node
.
props
.
filter
((
prop
)
=>
prop
.
name
===
'
name
'
)
node
.
props
=
node
.
props
.
filter
((
prop
)
=>
{
if
(
prop
.
type
===
NodeTypes
.
ATTRIBUTE
)
{
return
prop
.
name
===
'
name
'
}
else
if
(
prop
.
arg
?.
type
===
NodeTypes
.
SIMPLE_EXPRESSION
)
{
return
prop
.
arg
.
content
===
'
name
'
}
})
if
(
!
node
.
children
.
length
||
context
.
slot
.
fallbackContent
)
{
// 无后备内容或支持后备内容
return
genElement
(
node
,
context
)
...
...
@@ -154,9 +160,16 @@ function genSlot(node: SlotOutletNode, context: TemplateCodegenContext) {
function
genTemplate
(
node
:
TemplateNode
,
context
:
TemplateCodegenContext
)
{
const
slotProp
=
node
.
props
.
find
(
(
prop
)
=>
prop
.
type
===
NodeTypes
.
DIRECTIVE
&&
prop
.
name
===
'
slot
'
(
prop
)
=>
prop
.
type
===
NodeTypes
.
DIRECTIVE
&&
(
prop
.
name
===
'
slot
'
||
(
prop
.
name
===
'
bind
'
&&
prop
.
arg
?.
type
===
NodeTypes
.
SIMPLE_EXPRESSION
&&
prop
.
arg
.
content
===
'
slot
'
))
)
as
DirectiveNode
|
undefined
if
(
slotProp
&&
findSlotName
(
slotProp
))
{
// 为 bind 时,通常是作用域插槽生成的 vSlot.ts:197 createBindDirectiveNode('slot',...)
if
(
slotProp
&&
(
slotProp
.
name
===
'
bind
'
||
findSlotName
(
slotProp
)))
{
/**
* 仅百度、字节支持使用 block 作为命名插槽根节点
* 此处为了统一仅默认替换为view
...
...
@@ -213,7 +226,11 @@ function genElement(node: ElementNode, context: TemplateCodegenContext) {
let
tag
=
node
.
tag
// <template slot="left"/> => <block slot="left"/>
if
(
tag
===
'
template
'
)
{
tag
=
'
block
'
if
(
findProp
(
node
,
'
slot
'
))
{
tag
=
'
view
'
}
else
{
tag
=
'
block
'
}
}
if
(
node
.
tagType
===
ElementTypes
.
COMPONENT
)
{
tag
=
hyphenate
(
tag
)
...
...
packages/uni-mp-compiler/src/transforms/transformSlot.ts
浏览文件 @
e54d1f76
...
...
@@ -2,9 +2,11 @@ import {
AttributeNode
,
createCompilerError
,
createCompoundExpression
,
createSimpleExpression
,
DirectiveNode
,
ErrorCodes
,
ExpressionNode
,
findProp
,
isBindKey
,
isStaticExp
,
NodeTypes
,
...
...
@@ -14,16 +16,21 @@ import {
import
{
camelize
}
from
'
@vue/shared
'
import
{
RENDER_SLOT
}
from
'
../runtimeHelpers
'
import
{
genExpr
}
from
'
../codegen
'
import
{
TransformContext
}
from
'
../transform
'
import
{
isVForScope
,
TransformContext
}
from
'
../transform
'
import
{
processProps
}
from
'
./transformElement
'
import
{
rewriteExpression
}
from
'
./utils
'
import
{
createAttributeNode
,
createBindDirectiveNode
,
}
from
'
@dcloudio/uni-cli-shared
'
export
function
rewriteSlot
(
node
:
SlotOutletNode
,
context
:
TransformContext
)
{
let
slotName
:
string
|
ExpressionNode
=
`"default"`
let
hasOtherDir
=
false
const
nonNameProps
:
(
AttributeNode
|
DirectiveNode
)[]
=
[]
for
(
let
i
=
0
;
i
<
node
.
props
.
length
;
i
++
)
{
const
p
=
node
.
props
[
i
]
const
{
props
}
=
node
for
(
let
i
=
0
;
i
<
props
.
length
;
i
++
)
{
const
p
=
props
[
i
]
if
(
p
.
type
===
NodeTypes
.
ATTRIBUTE
)
{
if
(
p
.
value
)
{
if
(
p
.
name
===
'
name
'
)
{
...
...
@@ -65,12 +72,31 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) {
}
})
if
(
properties
.
length
)
{
const
slotKey
=
parseScopedSlotKey
(
context
)
const
nameProps
=
findProp
(
node
,
'
name
'
)
if
(
!
nameProps
)
{
// 生成默认的 default 插槽名
if
(
slotKey
)
{
props
.
push
(
createBindDirectiveNode
(
'
name
'
,
rewriteExpression
(
createSimpleExpression
(
'
"default-"+
'
+
slotKey
),
context
).
content
)
)
}
else
{
props
.
push
(
createAttributeNode
(
'
name
'
,
'
default
'
))
}
}
rewriteExpression
(
createCompoundExpression
([
context
.
helperString
(
RENDER_SLOT
)
+
'
(
'
,
slotName
,
'
,
'
,
`{
${
properties
.
join
(
'
,
'
)}
}`
,
`
${
slotKey
?
'
,
'
+
slotKey
:
''
}
`
,
'
)
'
,
]),
context
...
...
@@ -79,6 +105,21 @@ export function rewriteSlot(node: SlotOutletNode, context: TransformContext) {
}
}
function
parseScopedSlotKey
(
context
:
TransformContext
)
{
let
{
currentScope
}
=
context
const
indexs
:
string
[]
=
[]
while
(
currentScope
)
{
if
(
isVForScope
(
currentScope
))
{
indexs
.
push
(
currentScope
.
indexAlias
)
}
currentScope
=
currentScope
.
parent
!
}
const
inFor
=
!!
indexs
.
length
if
(
inFor
)
{
return
indexs
.
reverse
().
join
(
`+'-'+`
)
}
}
function
transformProperty
(
dir
:
DirectiveNode
,
context
:
TransformContext
)
{
if
(
!
dir
.
arg
||
!
dir
.
exp
)
{
return
...
...
packages/uni-mp-compiler/src/transforms/utils.ts
浏览文件 @
e54d1f76
...
...
@@ -19,6 +19,7 @@ import {
NodeTypes
,
SimpleExpressionNode
,
SourceLocation
,
TransformContext
as
VueTransformContext
,
}
from
'
@vue/compiler-core
'
import
{
walk
,
BaseNode
}
from
'
estree-walker
'
import
{
isUndefined
,
parseExpr
}
from
'
../ast
'
...
...
@@ -96,9 +97,9 @@ export function rewriteExpressionWithoutProperty(
}
export
function
rewriteExpression
(
node
:
ExpressionNode
,
context
:
TransformContext
,
context
:
TransformContext
|
VueTransformContext
,
babelNode
?:
Expression
,
scope
:
CodegenScope
=
context
.
currentScope
,
scope
:
CodegenScope
=
(
context
as
TransformContext
)
.
currentScope
,
{
property
,
ignoreLiteral
}
=
{
property
:
true
,
ignoreLiteral
:
false
}
)
{
if
(
node
.
type
===
NodeTypes
.
SIMPLE_EXPRESSION
&&
node
.
isStatic
)
{
...
...
@@ -106,7 +107,7 @@ export function rewriteExpression(
}
if
(
!
babelNode
)
{
const
code
=
genExpr
(
node
)
babelNode
=
parseExpr
(
code
,
context
,
node
)
babelNode
=
parseExpr
(
code
,
context
as
TransformContext
,
node
)
if
(
!
babelNode
)
{
return
createSimpleExpression
(
code
)
}
...
...
@@ -119,8 +120,8 @@ export function rewriteExpression(
}
// wxs 等表达式
if
(
context
.
filters
?.
length
)
{
if
(
isReferencedByIds
(
babelNode
,
context
.
filters
))
{
if
(
(
context
as
TransformContext
)
.
filters
?.
length
)
{
if
(
isReferencedByIds
(
babelNode
,
(
context
as
TransformContext
)
.
filters
))
{
return
createSimpleExpression
(
genExpr
(
node
),
false
,
node
.
loc
)
}
}
...
...
packages/uni-mp-compiler/src/transforms/vSlot.ts
浏览文件 @
e54d1f76
...
...
@@ -194,6 +194,10 @@ function createVForTemplate(
)
{
const
key
=
'
s
'
+
context
.
scopes
.
vFor
const
keyProp
:
DirectiveNode
=
createBindDirectiveNode
(
'
key
'
,
key
)
const
slotProp
:
DirectiveNode
=
createBindDirectiveNode
(
'
slot
'
,
`i
${
context
.
scopes
.
vFor
}
`
)
const
vForProp
:
DirectiveNode
=
{
type
:
NodeTypes
.
DIRECTIVE
,
name
:
'
for
'
,
...
...
@@ -212,7 +216,7 @@ function createVForTemplate(
tag
:
'
template
'
,
type
:
NodeTypes
.
ELEMENT
,
tagType
:
ElementTypes
.
TEMPLATE
,
props
:
[
vForProp
,
keyProp
],
props
:
[
vForProp
,
keyProp
,
slotProp
],
isSelfClosing
:
false
,
codegenNode
:
undefined
,
children
:
slotElement
.
children
,
...
...
packages/uni-mp-toutiao/dist/uni.compiler.js
浏览文件 @
e54d1f76
...
...
@@ -2,6 +2,10 @@
var
initMiniProgramPlugin
=
require
(
'
@dcloudio/uni-mp-vite
'
);
var
path
=
require
(
'
path
'
);
var
uniShared
=
require
(
'
@dcloudio/uni-shared
'
);
var
uniCliShared
=
require
(
'
@dcloudio/uni-cli-shared
'
);
var
uniMpCompiler
=
require
(
'
@dcloudio/uni-mp-compiler
'
);
var
compilerCore
=
require
(
'
@vue/compiler-core
'
);
function
_interopDefaultLegacy
(
e
)
{
return
e
&&
typeof
e
===
'
object
'
&&
'
default
'
in
e
?
e
:
{
'
default
'
:
e
};
}
...
...
@@ -29,7 +33,48 @@ var source = {
condition
:
condition
};
function
transformSwiper
(
node
)
{
if
(
node
.
type
!==
1
/* ELEMENT */
||
node
.
tag
!==
'
swiper
'
)
{
return
;
}
const
disableTouchProp
=
compilerCore
.
findProp
(
node
,
'
disable-touch
'
,
false
,
true
);
if
(
!
disableTouchProp
)
{
return
;
}
const
{
props
}
=
node
;
if
(
disableTouchProp
.
type
===
6
/* ATTRIBUTE */
)
{
// <swiper disable-touch/> => <swiper :touchable="false"/>
props
.
splice
(
props
.
indexOf
(
disableTouchProp
),
1
,
uniCliShared
.
createBindDirectiveNode
(
'
touchable
'
,
'
false
'
));
}
else
{
if
(
disableTouchProp
.
exp
)
{
// <swiper :disable-touch="true"/> => <swiper :touchable="!(true)"/>
let
touchable
=
''
;
if
(
disableTouchProp
.
exp
.
type
===
4
/* SIMPLE_EXPRESSION */
)
{
if
(
disableTouchProp
.
exp
.
content
===
'
true
'
)
{
touchable
=
'
false
'
;
}
else
if
(
disableTouchProp
.
exp
.
content
===
'
false
'
)
{
touchable
=
'
true
'
;
}
}
props
.
splice
(
props
.
indexOf
(
disableTouchProp
),
1
,
uniCliShared
.
createBindDirectiveNode
(
'
touchable
'
,
touchable
||
`!(
${
uniMpCompiler
.
genExpr
(
disableTouchProp
.
exp
)}
)`
));
}
}
}
const
projectConfigFilename
=
'
project.config.json
'
;
const
nodeTransforms
=
[
uniCliShared
.
transformRef
,
transformSwiper
,
uniCliShared
.
transformMatchMedia
,
uniCliShared
.
transformComponentLink
,
];
const
compilerOptions
=
{
isNativeTag
:
uniShared
.
isNativeTag
,
isCustomElement
:
uniShared
.
isCustomElement
,
nodeTransforms
,
};
const
miniProgram
=
{
class
:
{
array
:
false
,
...
...
@@ -72,7 +117,7 @@ const options = {
${
filter
.
code
}
</sjs>`
;
},
},
extname
:
'
.ttml
'
}),
},
extname
:
'
.ttml
'
,
compilerOptions
}),
style
:
{
extname
:
'
.ttss
'
,
},
...
...
packages/uni-mp-toutiao/src/compiler/options.ts
浏览文件 @
e54d1f76
...
...
@@ -74,6 +74,7 @@ ${filter.code}
},
},
extname
:
'
.ttml
'
,
compilerOptions
,
},
style
:
{
extname
:
'
.ttss
'
,
...
...
packages/uni-mp-vue/dist/vue.runtime.esm.js
浏览文件 @
e54d1f76
...
...
@@ -5016,7 +5016,7 @@ function vFor(source, renderItem) {
return
ret
;
}
function
renderSlot
(
name
,
props
=
{})
{
function
renderSlot
(
name
,
props
=
{}
,
key
)
{
const
instance
=
getCurrentInstance
();
const
vueIds
=
instance
.
attrs
.
vI
;
if
(
!
vueIds
)
{
...
...
@@ -5025,14 +5025,14 @@ function renderSlot(name, props = {}) {
if
(
!
instance
.
parent
&&
!
instance
.
isMounted
)
{
// 头条小程序首次 render 时,还没有 parent
onMounted
(()
=>
{
renderSlot
(
name
,
props
);
renderSlot
(
name
,
props
,
key
);
},
instance
);
return
;
}
const
invoker
=
findScopedSlotInvoker
(
vueIds
.
split
(
'
,
'
)[
0
],
instance
);
// 可能不存在,因为插槽不是必需的
if
(
invoker
)
{
invoker
(
name
,
props
);
invoker
(
name
,
props
,
key
);
}
}
function
findScopedSlotInvoker
(
vueId
,
instance
)
{
...
...
@@ -5063,13 +5063,18 @@ function withScopedSlot(fn, { name, path, vueId, }) {
else
{
invoker
.
slots
[
name
].
fn
=
fn
;
}
// 返回单元素数组,因为 scoped slot 被转换成了 for 循环
return
[
invoker
.
slots
[
name
].
data
];
return
invoker
.
slots
[
name
].
data
;
}
function
createScopedSlotInvoker
(
instance
)
{
const
invoker
=
(
slotName
,
args
)
=>
{
const
invoker
=
(
slotName
,
args
,
key
)
=>
{
const
slot
=
invoker
.
slots
[
slotName
];
slot
.
data
=
slot
.
fn
(
args
,
0
,
0
);
const
hasKey
=
typeof
key
!==
'
undefined
'
;
key
=
(
key
||
'
0
'
)
+
''
;
if
(
!
hasKey
)
{
// 循环第一个 slot 时,重置 data
slot
.
data
=
{};
}
slot
.
data
[
key
]
=
slot
.
fn
(
args
,
key
,
slotName
+
(
hasKey
?
'
-
'
+
key
:
''
));
// TODO 简单的 forceUpdate,理论上,可以仅对 scoped slot 部分数据 diff 更新
instance
.
proxy
.
$forceUpdate
();
};
...
...
@@ -5090,7 +5095,7 @@ function setupDevtoolsPlugin() {
const
o
=
(
value
)
=>
vOn
(
value
);
const
f
=
(
source
,
renderItem
)
=>
vFor
(
source
,
renderItem
);
const
r
=
(
name
,
props
)
=>
renderSlot
(
name
,
props
);
const
r
=
(
name
,
props
,
key
)
=>
renderSlot
(
name
,
props
,
key
);
const
w
=
(
fn
,
options
)
=>
withScopedSlot
(
fn
,
options
);
const
s
=
(
value
)
=>
stringifyStyle
(
value
);
const
c
=
(
str
)
=>
camelize
(
str
);
...
...
packages/uni-mp-vue/src/helpers/index.ts
浏览文件 @
e54d1f76
...
...
@@ -18,7 +18,8 @@ export const f: typeof vFor = (
source
:
any
,
renderItem
:
(...
args
:
any
[])
=>
VForItem
)
=>
vFor
(
source
,
renderItem
)
export
const
r
:
typeof
renderSlot
=
(
name
,
props
)
=>
renderSlot
(
name
,
props
)
export
const
r
:
typeof
renderSlot
=
(
name
,
props
,
key
)
=>
renderSlot
(
name
,
props
,
key
)
export
const
w
:
typeof
withScopedSlot
=
(
fn
,
options
)
=>
withScopedSlot
(
fn
,
options
)
export
const
s
:
typeof
stringifyStyle
=
(
value
)
=>
stringifyStyle
(
value
)
...
...
packages/uni-mp-vue/src/helpers/renderSlot.ts
浏览文件 @
e54d1f76
...
...
@@ -2,7 +2,11 @@ import type { ComponentInternalInstance } from 'vue'
import
type
{
ScopedSlotInvokers
}
from
'
./withScopedSlot
'
import
{
onMounted
,
getCurrentInstance
}
from
'
vue
'
export
function
renderSlot
(
name
:
string
,
props
:
Data
=
{})
{
export
function
renderSlot
(
name
:
string
,
props
:
Data
=
{},
key
?:
string
|
number
)
{
const
instance
=
getCurrentInstance
()
as
ComponentInternalInstance
const
vueIds
=
instance
.
attrs
.
vI
as
string
if
(
!
vueIds
)
{
...
...
@@ -11,14 +15,14 @@ export function renderSlot(name: string, props: Data = {}) {
if
(
!
instance
.
parent
&&
!
instance
.
isMounted
)
{
// 头条小程序首次 render 时,还没有 parent
onMounted
(()
=>
{
renderSlot
(
name
,
props
)
renderSlot
(
name
,
props
,
key
)
},
instance
)
return
}
const
invoker
=
findScopedSlotInvoker
(
vueIds
.
split
(
'
,
'
)[
0
],
instance
)
// 可能不存在,因为插槽不是必需的
if
(
invoker
)
{
invoker
(
name
,
props
)
invoker
(
name
,
props
,
key
)
}
}
...
...
packages/uni-mp-vue/src/helpers/withScopedSlot.ts
浏览文件 @
e54d1f76
...
...
@@ -7,16 +7,19 @@ export interface ScopedSlotInvokers {
}
interface
ScopedSlotFn
{
(
args
:
Data
,
key
:
number
,
index
:
number
):
Record
<
string
,
any
>
(
args
:
Data
,
key
:
string
,
slotName
:
string
):
Record
<
string
,
any
>
path
:
string
}
interface
ScopedSlotData
{
[
key
:
string
]:
Data
}
interface
ScopedSlotInvoker
{
(
slotName
:
string
,
args
:
Data
):
void
(
slotName
:
string
,
args
:
Data
,
key
?:
string
|
number
):
void
slots
:
{
[
slotName
:
string
]:
{
fn
:
ScopedSlotFn
data
:
Data
data
:
ScopedSlot
Data
}
}
}
...
...
@@ -48,14 +51,23 @@ export function withScopedSlot(
}
else
{
invoker
.
slots
[
name
].
fn
=
fn
}
// 返回单元素数组,因为 scoped slot 被转换成了 for 循环
return
[
invoker
.
slots
[
name
].
data
]
return
invoker
.
slots
[
name
].
data
}
function
createScopedSlotInvoker
(
instance
:
ComponentInternalInstance
)
{
const
invoker
:
ScopedSlotInvoker
=
(
slotName
:
string
,
args
:
Data
)
=>
{
const
invoker
:
ScopedSlotInvoker
=
(
slotName
:
string
,
args
:
Data
,
key
?:
string
|
number
)
=>
{
const
slot
=
invoker
.
slots
[
slotName
]
slot
.
data
=
slot
.
fn
(
args
,
0
,
0
)
const
hasKey
=
typeof
key
!==
'
undefined
'
key
=
(
key
||
'
0
'
)
+
''
if
(
!
hasKey
)
{
// 循环第一个 slot 时,重置 data
slot
.
data
=
{}
}
slot
.
data
[
key
]
=
slot
.
fn
(
args
,
key
,
slotName
+
(
hasKey
?
'
-
'
+
key
:
''
))
// TODO 简单的 forceUpdate,理论上,可以仅对 scoped slot 部分数据 diff 更新
instance
.
proxy
!
.
$forceUpdate
()
}
...
...
packages/uni-mp-weixin/dist/uni.api.esm.js
浏览文件 @
e54d1f76
...
...
@@ -833,16 +833,39 @@ const previewImage = {
},
};
const
mocks
=
[
'
__route__
'
,
'
__wxExparserNodeId__
'
,
'
__wxWebviewId__
'
];
const
getProvider
=
initGetProvider
({
oauth
:
[
'
weixin
'
],
share
:
[
'
weixin
'
],
payment
:
[
'
wxpay
'
],
push
:
[
'
weixin
'
],
});
});
function
initComponentMocks
(
component
)
{
const
res
=
Object
.
create
(
null
);
mocks
.
forEach
((
name
)
=>
{
res
[
name
]
=
component
[
name
];
});
return
res
;
}
/**
* 微信小程序内部会 Object.keys(vm),导致告警
* Avoid app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead.
* @returns
*/
function
createSelectorQuery
()
{
const
query
=
wx
.
createSelectorQuery
();
const
oldIn
=
query
.
in
;
query
.
in
=
function
newIn
(
component
)
{
return
oldIn
.
call
(
this
,
initComponentMocks
(
component
));
};
return
query
;
}
var
shims
=
/*#__PURE__*/
Object
.
freeze
({
__proto__
:
null
,
getProvider
:
getProvider
getProvider
:
getProvider
,
createSelectorQuery
:
createSelectorQuery
});
var
protocols
=
/*#__PURE__*/
Object
.
freeze
({
...
...
packages/uni-mp-weixin/src/api/shims.ts
浏览文件 @
e54d1f76
import
{
initGetProvider
}
from
'
@dcloudio/uni-mp-core
'
import
{
initGetProvider
,
MPComponentInstance
}
from
'
@dcloudio/uni-mp-core
'
import
{
mocks
}
from
'
../runtime/parseOptions
'
export
const
getProvider
=
initGetProvider
({
oauth
:
[
'
weixin
'
],
...
...
@@ -6,3 +7,28 @@ export const getProvider = initGetProvider({
payment
:
[
'
wxpay
'
],
push
:
[
'
weixin
'
],
})
function
initComponentMocks
(
component
:
|
WechatMiniprogram
.
Component
.
TrivialInstance
|
WechatMiniprogram
.
Page
.
TrivialInstance
)
{
const
res
:
MPComponentInstance
=
Object
.
create
(
null
)
mocks
.
forEach
((
name
)
=>
{
res
[
name
]
=
component
[
name
]
})
return
res
}
/**
* 微信小程序内部会 Object.keys(vm),导致告警
* Avoid app logic that relies on enumerating keys on a component instance. The keys will be empty in production mode to avoid performance overhead.
* @returns
*/
export
function
createSelectorQuery
()
{
const
query
=
wx
.
createSelectorQuery
()
const
oldIn
=
query
.
in
query
.
in
=
function
newIn
(
component
)
{
return
oldIn
.
call
(
this
,
initComponentMocks
(
component
))
}
return
query
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录