在ArkUI的ETS中实现【插槽】的功能 原创 精华

发布于 2021-11-23 22:54
浏览
6收藏

【本文正在参与优质创作者激励】
距离ETS的发布也有一段时间,也有不少小伙伴通过ETS制作出很多精美的页面,但在我查阅ETS的组件和API中发现,现有版本的ETS并没有插槽的功能。经过一段时间的探索终于找到曲线救国方式实现插槽功能,得以让组件之间进行解耦。

什么是插槽

了解插槽的小伙伴可以跳过
vue官方定义是:插槽是一套内容分发的API,当组件渲染的时候,<slot></slot> 将会被替换为“Your Profile”。插槽内可以包含任何模板代码。
通俗一点就是插槽就像一个占位符,将组件外的内容通过API分发至组件内。

实现步骤

定义一个slot类

旨在提供一个具名的插槽,故定义一个slot类做后续委托。这不是实现的关键点,也可不定义。

class Slot{
  name:string="default"
  builder:any

  constructor (name:string,builder:any){
    this.name=name;
    this.builder=builder
  }
}

创建一个组件CompA

创建一个自定义组件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)
          }
        }
      }
    }
  }
}

构建页面的组件

构建一个Index的页面,在页面内创建两个Buider bulder1builder2,并实例化两个Slot类slot1slot2,将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%')
  }
}

显示效果

在ArkUI的ETS中实现【插槽】的功能-鸿蒙HarmonyOS技术社区

通过图片可以看到,builder1,builder2真实位置是在了CompA的slot处。

重点

上面就提到Slot类可以不用创建,因为实现原理是通过ForEach+Builder实现,也可以将Builder通过函数绑定到组件内。
再看一下官方文档中ForEach
在ArkUI的ETS中实现【插槽】的功能-鸿蒙HarmonyOS技术社区

全部代码供参考

@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
  }
}

©著作权归作者和HarmonyOS技术社区共同所有,如需转载,请注明出处,否则将追究法律责任
已于2021-11-24 16:01:06修改
8
收藏 6
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐