距离ETS的发布也有一段时间,也有不少小伙伴通过ETS制作出很多精美的页面,但在我查阅ETS的组件和API中发现,现有版本的ETS并没有插槽的功能。经过一段时间的探索终于找到曲线救国方式实现插槽功能,得以让组件之间进行解耦。
了解插槽的小伙伴可以跳过
vue官方定义是:插槽是一套内容分发的API,当组件渲染的时候, 将会被替换为“Your Profile”。插槽内可以包含任何模板代码。
通俗一点就是插槽就像一个占位符,将组件外的内容通过API分发至组件内。
旨在提供一个具名的插槽,故定义一个slot类做后续委托。这不是实现的关键点,也可不定义。
复制
class Slot{ name:string="default" builder:any constructor (name:string,builder:any){ this.name=name; this.builder=builder } }
1.
2.
3.
4.
5.
6.
7.
8.
9.
创建一个自定义组件CompA,并提供两个具名插槽的处理,一个defualt,一个slot2。
复制
@Component struct CompA{ @State text:string="" @State data:string[]=[] @State slot:Slot=new Slot(null) build(){ Column(){ Column(){ Text("CompA组件内的内容") .fontColor("#00F") .fontSize(16) .margin(10) } Column(){ Row(){ if(this.slot.name=="default"){ ForEach(["这是默认插槽【default】"], this.slot.builder) } if(this.slot.name=="slot2"){ ForEach(this.data, this.slot.builder) } } } } } }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
构建一个Index的页面,在页面内创建两个Buider bulder1 ,builder2,并实例化两个Slot类slot1、slot2,将builder1,builder2分别给到slot1,slot2。
builder1内通过Text组件显示一段文字。
builder2内通构建稍微复杂一点的模型,设置一个文字和二维码。
复制
@Entry @Component struct Index { @Builder builder1(str:string){ Text(str).fontSize(18).fontColor("#f00") } @Builder builder2(obj:any){ Column(){ Row(){ Text(obj.title).fontSize(16) } Row(){ QRCode(obj.title).width(100).height(100) }.margin(10) }.margin(10) } slot1:Slot=new Slot(this.builder1) slot2:Slot=new Slot(this.builder2,"slot2") build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Column(){ CompA(){ Text("这样是不会显示的").fontSize(24) } CompA({slot:this.slot1}) CompA({slot:this.slot2,data:[{title:"这是第二个插槽"},{title:"http://www.baidu.com"}]}) } } .width('100%') .height('100%') } }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
显示效果:
通过图片可以看到,builder1,builder2真实位置是在了CompA的slot处。
上面就提到Slot类可以不用创建,因为实现原理是通过ForEach+Builder实现,也可以将Builder通过函数绑定到组件内。
再看一下官方文档中ForEach:
复制
@Entry @Component struct Index { @Builder builder1(str:string){ Text(str).fontSize(18).fontColor("#f00") } @Builder builder2(obj:any){ Column(){ Row(){ Text(obj.title).fontSize(16) } Row(){ QRCode(obj.title).width(100).height(100) }.margin(10) }.margin(10) } slot1:Slot=new Slot(this.builder1) slot2:Slot=new Slot(this.builder2,"slot2") build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Column(){ CompA(){ Text("这样是不会显示的").fontSize(24) } CompA({slot:this.slot1}) CompA({slot:this.slot2,data:[{title:"这是第二个插槽"},{title:"http://www.baidu.com"}]}) } } .width('100%') .height('100%') } } @Component struct CompA{ @State text:string="" @State data:string[]=[] @State slot:Slot=new Slot(null) build(){ Column(){ Column(){ Text("CompA组件内的内容") .fontColor("#00F") .fontSize(16) .margin(10) } Column(){ Row(){ if(this.slot.name=="default"){ ForEach(["这是默认插槽【default】"], this.slot.builder) } if(this.slot.name=="slot2"){ ForEach(this.data, this.slot.builder) } } } } } } class Slot{ name:string="default" builder:any constructor (builder:any,name?:string){ name && (this.name=name); this.builder=builder } }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.