Quellcode durchsuchen

feat: 新增弹窗相关组件

YuJing vor 1 Monat
Ursprung
Commit
e4536a072a

+ 4 - 0
commons/basic/Index.ets

@@ -113,6 +113,10 @@ export * from '@mumu/crop'
 
 export * from './src/main/ets/models'
 
+// 弹窗相关导出
+export * from './src/main/ets/components/DiaLogComp/DiaLogComp'
+export * from './src/main/ets/components/DiaLogComp/DiaLogControl'
+export * from './src/main/ets/components/DiaLogComp/DiaLogSheetComp'
 
 
 

+ 76 - 0
commons/basic/src/main/ets/components/DiaLogComp/DiaLogComp.ets

@@ -0,0 +1,76 @@
+import { BasicType } from "../../../../../Index"
+import { DiaLogCompControl } from "./DiaLogControl"
+
+@ComponentV2
+export struct DiaLogComp {
+  @Param controller: DiaLogCompControl = new DiaLogCompControl(this.getUIContext())
+  @Param param: BasicType = {}
+
+  @BuilderParam container: () => void = this.containerComp
+
+  build() {
+    NavDestination(){
+      Column(){
+        Column(){
+          this.container()
+        }
+        // 屏蔽外部容器的点击事件
+        .onClick(() => {})
+        .scale({ x: this.controller.opacity_, y: this.controller.opacity_ })
+      }
+      .width("100%")
+      .height("100%")
+      .opacity(this.controller.opacity_)
+      .backgroundColor(this.controller.bgc)
+      .justifyContent(FlexAlign.Center)
+      .alignItems(HorizontalAlign.Center)
+      .onClick(() => { this.controller._onBackPress(0)})
+      .onAppear(() => { this.controller.appear() })
+    }
+    .hideTitleBar(true)
+    .mode(NavDestinationMode.DIALOG)
+    .onBackPressed(() => { return this.controller._onBackPress(0) })
+    .systemTransition(NavigationSystemTransitionType.NONE)
+  }
+
+  @Builder
+  containerComp(){
+    Column() {
+        Text(this.param.text ?? '一个弹窗')
+          .fontColor(Color.Black)
+          .lineHeight(18)
+          .fontSize(18)
+          .textAlign(TextAlign.Center)
+          .margin({ bottom: 18 })
+      Row() {
+        Text('取消')
+          .fontSize(16)
+          .fontWeight(400)
+          .borderRadius(36)
+          .fontColor(Color.Black)
+          .backgroundColor('#F5F5F7')
+          .padding({ left: 36, top: 9, right: 36, bottom: 9})
+          .onClick(() => {
+            this.controller._onBackPress(0)
+          })
+
+        Text('确定')
+          .fontSize(16)
+          .fontWeight(400)
+          .borderRadius(36)
+          .fontColor(Color.Black)
+          .padding({ left: 36, top: 9, right: 36, bottom: 9})
+          .backgroundColor(this.param.color ?? '#FFFECF2F')
+          .onClick(() => {
+            this.controller._onBackPress(1)
+          })
+      }
+      .justifyContent(FlexAlign.SpaceBetween)
+      .width('100%')
+    }
+    .width(280)
+    .borderRadius(8)
+    .backgroundColor(Color.White)
+    .padding({ top: 28, left: 32, right: 32, bottom: 20 })
+  }
+}

+ 107 - 0
commons/basic/src/main/ets/components/DiaLogComp/DiaLogControl.ets

@@ -0,0 +1,107 @@
+import { BasicType, yTRouter } from "../../../../../Index";
+
+// 中间弹窗
+@ObservedV2
+export class DiaLogCompControl{
+  @Trace bgc: ResourceColor = 'rgba(0, 0, 0, 0.6)'
+
+  @Trace opacity_: number = 0
+
+  conText: UIContext;
+
+  isBack: boolean = false
+
+  appear(): void {
+    this.conText.animateTo({ duration: 300 }, () => {
+      this.opacity_ = 1
+    })
+  }
+
+  _onBackPress: (ans?: ESObject) => boolean = (ans: ESObject) => {
+    if(this.isBack) return true
+
+    this.isBack = true
+
+    this.conText.animateTo({ duration: 300 }, () => {
+      this.opacity_ = 0
+      setTimeout(() => {
+        yTRouter.pop(ans ?? 0, false)
+      }, 300)
+    })
+    return true
+  }
+
+  constructor(conText: UIContext) {
+    this.conText = conText
+  }
+}
+
+
+// 底部弹窗
+@ObservedV2
+export class DiaLogSheetControl{
+  @Trace bgc: ResourceColor = 'rgba(0, 0, 0, 0.6)'
+  @Trace h_: Length = 0
+  @Trace opacity_: number = 0
+  @Trace offsetY_: number | string = 0
+
+  startY: number = 0
+  isBack: boolean = false
+  containerH: number = 0
+  conText: UIContext;
+
+  appear(){
+    this.conText.animateTo({duration: 300}, () => {
+      this.offsetY_ = '-100%'
+      this.opacity_ = 1
+    })
+  }
+
+  edgeEffect(event: TouchEvent){
+    event.stopPropagation();
+
+    if (event.type === TouchType.Down) {
+      // 记录初始触摸坐标
+      this.startY = event.touches[0].displayY as number
+    } else if (event.type === TouchType.Move) {
+      // 计算滑动偏移量
+      this.conText.animateTo({ duration:200, curve: Curve.EaseInOut }, () => {
+        const deltaY = this.startY - event.touches[0].displayY
+        this.h_ = Math.sqrt(Math.abs(deltaY)) * (deltaY >= 0 ? 10: -10)
+      })
+    } else if (event.type === TouchType.Up) {
+      // 滑动结束处理
+      this.conText.animateTo({ duration:300, curve: Curve.Smooth }, () => {
+        if(this.h_ <= -this.containerH/3) {
+          this._onBackPress()
+        } else {
+          this.h_ = 0
+        }
+      })
+    }
+  }
+
+  _onBackPress: (ans?: ESObject) => boolean = (ans: ESObject) => {
+    if(this.isBack) return true
+
+    this.isBack = true
+
+    this.conText.animateTo({ duration: 300, curve: Curve.Smooth }, () => {
+      this.offsetY_ = 0
+      this.opacity_ = 0
+
+      setTimeout(() => {
+        yTRouter.pop(ans ?? 0, false)
+      }, 300)
+    })
+    return true
+  }
+
+  constructor(conText: UIContext) {
+    this.conText = conText
+  }
+}
+
+
+
+

+ 89 - 0
commons/basic/src/main/ets/components/DiaLogComp/DiaLogSheetComp.ets

@@ -0,0 +1,89 @@
+import { BasicType } from "../../../../../Index"
+import { DiaLogSheetControl } from "./DiaLogControl"
+
+@ComponentV2
+export struct DiaLogSheetComp {
+  @Param control: DiaLogSheetControl = new DiaLogSheetControl(this.getUIContext())
+  @Param params: Array<BasicType> = []
+
+  @BuilderParam container: (_: () => void) => void = this.containerComp
+
+  build() {
+    NavDestination() {
+      Column() {
+        Column() {
+          Column(){
+            this.containerComp()
+          }
+          .onAreaChange((o, n) => {
+            this.control.containerH = n.height as number
+          })
+
+          Blank()
+            .height(this.control.h_)
+            .backgroundColor(Color.White)
+        }
+        .onClick(() => {})
+        // 阻塞事件冒泡: 不会触发父组件的点击事件
+        .hitTestBehavior(HitTestMode.Block)
+        .onTouch((event: TouchEvent) => { this.control.edgeEffect(event) })
+        .offset({ y: this.control.h_ < 0 ? Math.abs(this.control.h_ as number) : 0 })
+      }
+      .width('100%')
+      .height('200%')
+      .opacity(this.control.opacity_)
+      .backgroundColor(this.control.bgc)
+      .offset({ y: this.control.offsetY_ })
+      .justifyContent(FlexAlign.End)
+      .onAppear(() => { this.control.appear() })
+      .alignItems(HorizontalAlign.Center)
+      .gesture(
+        TapGesture()
+          .onAction(() => {
+            this.control._onBackPress()
+          })
+      )
+    }
+    .hideTitleBar(true)
+    .mode(NavDestinationMode.DIALOG)
+    .onBackPressed(() => { return this.control._onBackPress() })
+    .systemTransition(NavigationSystemTransitionType.NONE)
+  }
+
+  @Builder
+  containerComp(){
+    Column(){
+      ForEach(this.params, (item: BasicType, index) => {
+        Row(){
+          Text(item.text)
+            .fontSize(16)
+            .textAlign(TextAlign.Center)
+        }
+        .width("100%")
+        .onClick(() => { this.control._onBackPress(item.text) })
+        .alignItems(VerticalAlign.Center)
+        .justifyContent(FlexAlign.Center)
+        .padding({ top: 24, bottom: 24 })
+
+        Divider().width("80%").height(1).backgroundColor('#000000F2')
+      })
+
+      Row(){
+        Text(`取消`)
+          .fontSize(16)
+          .textAlign(TextAlign.Center)
+      }
+      .width("100%")
+      .alignItems(VerticalAlign.Center)
+      .justifyContent(FlexAlign.Center)
+      .padding({ top: 24, bottom: 24 })
+      .onClick(() => { this.control._onBackPress(0) })
+    }
+    .width("100%")
+    .padding({ bottom: 30 })
+    .backgroundColor(Color.White)
+    .justifyContent(FlexAlign.Center)
+    .alignItems(HorizontalAlign.Center)
+    .borderRadius({ topLeft: 8, topRight: 8 })
+  }
+}

+ 7 - 0
features/feature/src/main/ets/model/DiaLogParam.ets

@@ -0,0 +1,7 @@
+import { BasicType } from "basic"
+
+export interface DiaLogParam{
+  isCenter?: boolean
+  param?: BasicType
+  params?: Array<BasicType>
+}

+ 20 - 0
features/feature/src/main/ets/pages/DiaLogPage.ets

@@ -0,0 +1,20 @@
+import { DiaLogComp, DiaLogSheetComp } from 'basic';
+import { DiaLogParam } from '../model/DiaLogParam';
+
+@ComponentV2
+struct DiaLogPage {
+  @Param param: DiaLogParam = {}
+
+  build() {
+    if(this.param.isCenter ?? true) {
+      DiaLogComp({param: this.param.param})
+    } else {
+      DiaLogSheetComp({params: this.param.params})
+    }
+  }
+}
+
+@Builder
+function DiaLogBuilder(_: string, param: DiaLogParam) {
+    DiaLogPage({param: param})
+}

+ 4 - 0
features/feature/src/main/ets/utils/RouterUtrils.ets

@@ -4,4 +4,8 @@ export class RouterUtils{
   static router2BookItemDetailPage(){
     yTRouter.pushPathByName('BookItemDetailPage', null)
   }
+
+  static openDiaLog(){
+    
+  }
 }

+ 5 - 0
features/feature/src/main/resources/base/profile/router_map.json

@@ -24,6 +24,11 @@
       "name": "BookItemDetailPage",
       "pageSourceFile": "src/main/ets/pages/BookItemDetailPage.ets",
       "buildFunction": "BookItemDetailBuilder"
+    },
+    {
+      "name": "DiaLogPage",
+      "pageSourceFile": "src/main/ets/pages/DiaLogPage.ets",
+      "buildFunction": "DiaLogBuilder"
     }
   ]
 }