鸿蒙NEXT组件封装 | 使用类插槽特性封装一个抽屉组件

707 阅读1分钟

前言

因为自己写的一个小项目中需要比较多的自定义配置,所以需要一个抽屉模式弹窗。在gitee也看到有人封装了抽屉的第三方库,但是不是自己习惯的使用方式,所以为了贴合自己的使用习惯还是自己动手简单封装了一个😀。

他山之石

先贴上链接 DrawerLayout: 🔥🔥👍基于ArkTS基础组件封装的抽屉布局、侧边栏布局组件。 (gitee.com)

组件使用方式如下

1) 创建model
   @State model: DrawerLayout.Model = new DrawerLayout.Model()
  (2) 创建DrawerLayout
   DrawerLayout({
       // 1.绑定Model
       model: $model,
       // 2.侧边栏布局页面
       drawerView: () => {
         this.buildDrawerView();
       },
       // 3.内容布局页面
       contentView: () => {
         this.buildContentView();
       }
     })
  (3)model方法说明 
   //打开抽屉
   this.model.openDrawer()
   //关闭抽屉
   this.model.closeDrawer()
   //打开或者关闭抽屉
   this.model.openOrCloseDrawer()
  • 参数drawerView是展示抽屉内容组件函数
  • 参数contentView是展示主页面内容组件函数

与我个人使用冲突点在于主页面的内容也需要当作一个组件传进去展示。我比较喜欢主页面正常布局,组件拿来嵌入主页面的方式。我参考了一下源码然后进行了一些改造,主要有以下特性

  • 改为抽屉组件嵌入主页面方式
  • 组件只负责抽屉部分展示
  • 组件内外都可以控制显隐

封装设计

1、实现插槽涉及特性

  • @Builder:装饰自定义构建函数。
  • @BuilderParam:接收自定义构建函数(@Builder装饰的方法)。跳转官方文档

2、初步实现带插槽的组件

  • 因为内容可能比较多使用滚动容器Scroll包裹
  • @BuilderParam 需要默认赋一个@Builder装饰的函数否则会报错
@Component
struct  CusDrawer {
  @Builder defaultBuilder() {};
  @BuilderParam drawerContent: () => void = this.defaultBuilder;
  build() {
    Scroll() {
      this.drawerContent()
    }
  }
}

3、实现组件从右侧滑入滑出

  • @Link visible外部传入变量visible,用来控制显隐并支持组件内外都可以控制。
  • position将组件定位在右侧
  • animation给组件加入滑入滑出动画
  • 并将组件导出
@Component
struct  CusDrawer {
  @Link visible: boolean
  @Builder customBuilder() {};
  @BuilderParam drawerContent: () => void = this.customBuilder;
  build() {
    Scroll() {
      this.drawerContent()
    }
    .position({x: this.visible ? '50%' : '100%', y:0})
    .width('50%')
    .height('100%')
    .borderRadius({
      topLeft: 20,
      bottomLeft: 20
    })
    .animation({
      duration: 500
    })
  }
}
export default  CusDrawer

4、引入组件测试

  • 使用onTouch,设计左滑打开右滑关闭我这里设计滑动幅度超过100触发
  • @Builder drawContent定义弹窗展示内容传入插槽
  • visible: $visible @Link语法
import CusDrawer from  '../components/cusDrawer'

@Entry
@Component
struct Index {
  @State visible:boolean = false
  @State curX:number = 0
  @Builder drawContent() {
    Column() {
      Text('抽屉文字').fontSize(40)
    }
  }
  build() {
    Column() {
      Text('main展示').fontSize(100).fontColor(Color.White)
      CusDrawer({drawerContent: this.drawContent, visible: $visible})
    }.alignItems(HorizontalAlign.Start)
    .height('100%')
    .width('100%')
    .backgroundColor(Color.Black)
    .onTouch((e) => {
      if(e.type === TouchType.Down) {
        // 按下屏幕存储x轴初始位置
        this.curX = e.touches[0].x
      } else if (e.type === TouchType.Up) {
        // 抬起位置计算是左滑还是右滑
        if(this.curX - e.touches[0].x > 100) {
          this.visible = true;
        } else if(this.curX - e.touches[0].x < -100) {
          this.visible = false;
        }
      }
    })
  }
}

最终实现效果展示

抽屉演示.gif

最后

核心功能就是这些,后面一些细节比如加个蒙版可以根据自己的需要自行扩展。