ArkTS 动态生成对话框的方式

3 篇文章 0 订阅
2 篇文章 0 订阅


动态生成持有 CustomDialogController 的组件,来实现动态生成对话框

代码

包括四个ets文件(MyDialogComponent、MyDialog、MyButton、MyBaseAdapter)

MyDialogComponent.ets

import { AlertParams, DateTimeParams, MyDialog, MyDialogParams, MyDialogType, MyObject, ProgressParams, PullUpButtonParams } from './MyDialog';
import { BaseAdapter } from './MyBaseAdapter';
import { MyButton } from './MyButton';


const color333333 = 0xff333333;
const line = 0xffcccccc;
const titleBarColor = 0xffE5431B;
const color999999 = 0xff999999;
const colorF9F9F9 = 0xffF9F9F9;
const colorF2F2F2 = 0xffF2F2F2;


@CustomDialog
struct AlertDialogBuilder {
  controller: CustomDialogController;
  params!: AlertParams;
  @State maxHeight: number = 0;
  heightForRoot: number = 0;
  heightForTitle: number = 0;

  aboutToAppear() {
    this.params.title ??= ""
    this.params.message ??= ""
    this.params.btnOK ??= "确定"
    this.params.btnCancel ??= ""
  }

  @Builder
  buildContent() {
    Column() {
      Column() {
        Row() {
          if (this.params.title!.length > 0) {
            Text(this.params.title)
              .fontColor(color333333)
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .padding({ bottom: 13 })
              .onAreaChange((_, newArea) => {
                let height = newArea.height as number;
                if (height != this.heightForTitle) {
                  this.heightForTitle = height;
                  this.refreshMaxHeight();
                }
              })
          } else {
            Blank().height(13)
          }
        }.constraintSize({ minHeight: 13 })

        Column() {
          Scroll() {
            Column() {
              Text(this.params.message).fontColor(color333333).fontSize(16)
            }
          }.scrollable(ScrollDirection.Vertical) //.edgeEffect(EdgeEffect.Spring)
        }.constraintSize({ maxHeight: this.maxHeight > 0 ? this.maxHeight : "100%" })

        Row() {
          if (this.params.btnCancel!.length > 0) {
            MyButton({
              text: this.params.btnCancel,
              buttonHeight: 44,
              click: () => {
                MyDialogParams.close(this.params);
                this.params.btnCancelClick?.();
              }
            }).layoutWeight(1)
          }
          if (this.params.btnCancel!.length > 0 && this.params.btnOK!.length > 0) {
            Blank().width(24)
          }
          if (this.params.btnOK!.length > 0) {
            MyButton({
              text: this.params.btnOK,
              buttonHeight: 44,
              click: () => {
                MyDialogParams.close(this.params);
                this.params.btnOKClick?.();
              }
            }).layoutWeight(1)
          }
        }.padding({ top: 24 })
      }.padding(24)
      .backgroundColor(Color.White)
      .borderRadius(10)
    }
    .margin({ left: 32, right: 32, top: 32, bottom: 32, })
    .onClick(() => {

    })
  }

  build() {
    Column() {
      this.buildContent()
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .width("100%")
    .height("100%")
    .onClick(() => {
      if (this.params.autoCancel) {
        MyDialogParams.close(this.params);
        this.params.cancel?.();
      }
    })
    .onAreaChange((_, newArea) => {
      let height = newArea.height as number;
      if (this.heightForRoot != height) {
        this.heightForRoot = height;
        this.refreshMaxHeight();
      }
    })
  }

  refreshMaxHeight() {
    if (this.heightForRoot > 0) {
      if (this.params.title!.length > 0 && this.heightForTitle == 0) return;
      let tempHeight = this.heightForRoot - (32 + 32) - (24 + this.heightForTitle + 13) - (24 + 44 + 24);
      if (tempHeight != this.maxHeight) {
        this.maxHeight = tempHeight;
      }
    }
  }
}

@CustomDialog
struct ProgressDialogBuilder {
  controller: CustomDialogController;
  params!: ProgressParams;
  @State progress: number = -1;
  @State message: string = "";

  aboutToAppear() {
    this.message = this.params.message ?? "";
    this.progress = this.params.progress ?? -1;
    if (this.progress >= 0) {
      this.params.updateProgress = (progress, message) => {
        this.progress = progress ?? 0;
        this.message = message ?? "";
      }
    }
  }

  @Builder
  buildContent() {
    Column() {
      if (this.progress >= 0) {
        Stack() {
          Progress({ value: this.progress, total: 100, type: ProgressType.Ring }).color(titleBarColor).style({ strokeWidth: 10, scaleCount: 10, scaleWidth: 10 })
            .width("100%").height("100%")
          Row() {
            Text(this.params.progress!.toFixed(1)).fontColor(color333333).fontSize(22).fontWeight(FontWeight.Bold)
            Text("%").fontColor(color333333).fontSize(12).fontWeight(FontWeight.Bold).padding({ left: 2, bottom: 3 })
          }.alignItems(VerticalAlign.Bottom)
        }.align(Alignment.Center).width(100).height(100)

        if (this.message.length > 0) {
          Text(this.message)
            .fontColor(color333333)
            .fontSize(18)
            .maxLines(6)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .padding({ top: 16, left: 8, right: 8, bottom: 8 })
        }
      } else {
        LoadingProgress().color(titleBarColor).width(100).height(100)
        if (this.message.length > 0) {
          Text(this.message)
            .fontColor(color333333)
            .fontSize(18)
            .maxLines(6)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .padding(8)
        }
      }
    }
    .padding(24)
    .backgroundColor(Color.White)
    .borderRadius(10)
    .margin({ left: 32, right: 32, top: 32, bottom: 32, })
    .onClick(() => {

    })
  }

  build() {
    Column() {
      this.buildContent()
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .width("100%")
    .height("100%")
    .onClick(() => {
      if (this.params.autoCancel) {
        MyDialogParams.close(this.params);
        this.params.cancel?.();
      }
    })
  }
}

@CustomDialog
struct PullUpButtonDialogBuilder {
  controller: CustomDialogController;
  params!: PullUpButtonParams;

  aboutToAppear() {
    this.params.btnList ??= [];
    this.params.btnCancel ??= "";
  }

  @Builder
  buildButton(btnName: string, index: number, isForCancel: boolean = false) {
    Text(btnName)
      .fontColor(color333333)
      .fontSize(16)
      .height(50)
      .textAlign(TextAlign.Center)
      .width("100%")
      .onClick(() => {
        MyDialogParams.close(this.params);
        if (!isForCancel) this.params.btnClick?.(btnName, index)
      })
  }

  build() {
    Column() {
      Column() {
        Column() {
          Scroll() {
            Column() {
              if (this.params.btnList.length > 0) {
                ForEach(this.params.btnList, (btnName: string, index: number) => {
                  this.buildButton(btnName, index)
                  Text().height(1).width("100%").backgroundColor(colorF2F2F2)
                })
              } else {
                // 没有展示的 button
              }
            }
          }.scrollable(ScrollDirection.Vertical).constraintSize({ maxHeight: "100%" }).backgroundColor(Color.White)
        }.layoutWeight(1).justifyContent(FlexAlign.End)

        if (this.params.btnCancel!.length > 0) {
          Column() {
            Text().width("100%").height(8).backgroundColor(colorF9F9F9);
            this.buildButton(this.params.btnCancel!, -1, true);
          }.backgroundColor(Color.White)
        }
      }.constraintSize({ maxHeight: "60%" }).justifyContent(FlexAlign.End)
    }.width("100%").height("100%").justifyContent(FlexAlign.End)
    .onClick(() => {
      if (this.params.autoCancel) {
        MyDialogParams.close(this.params);
        this.params.cancel?.();
      }
    })
  }
}

@CustomDialog
struct DateTimeDialogBuilder {
  controller: CustomDialogController;
  params!: DateTimeParams;
  private curDate: Date = new Date();

  aboutToAppear() {
    if (!this.params.selectedDate) this.params.selectedDate = new Date();
    this.curDate.setTime(this.params.selectedDate.getTime());

    if (typeof this.params.minDate === 'string') this.params.minDate = new Date(Date.parse(this.params.minDate as string));
    if (typeof this.params.maxDate === 'string') this.params.maxDate = new Date(Date.parse(this.params.maxDate as string));
    // 为了方便写,所以默认为空字符串
    this.params.btnOK ??= "";
    this.params.btnCancel ??= "";
  }

  @Builder
  builderTitleBar() {
    if ((this.params.title && this.params.title.length > 0) || (this.params.btnOK && this.params.btnOK.length > 0) || (this.params.btnCancel && this.params.btnCancel.length > 0)) {
      Row() {
        Row() {
          if (this.params.btnCancel!.length > 0 || this.params.btnOK!.length > 0) {
            Button(this.params.btnCancel!.length > 0 ? this.params.btnCancel : this.params.btnOK)
              .fontSize(16)
              .backgroundColor(Color.Transparent)
              .fontColor(color999999)
              .onClick(() => {
                MyDialogParams.close(this.params)
                this.params.btnCancelClick?.();
              })
              .visibility(this.params.btnCancel!.length > 0 ? Visibility.Visible : Visibility.Hidden)
          }
        }.constraintSize({ minWidth: 16 })

        Text(this.params.title)
          .fontSize(16)
          .padding({ left: 8, right: 8, top: 15, bottom: 15 })
          .fontColor(color333333)
          .maxLines(1)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .textAlign(TextAlign.Center)
          .layoutWeight(1)

        Row() {
          if (this.params.btnCancel!.length > 0 || this.params.btnOK!.length > 0) {
            Button(this.params.btnOK!.length > 0 ? this.params.btnOK : this.params.btnCancel)
              .fontSize(16)
              .backgroundColor(Color.Transparent)
              .fontColor(titleBarColor)
              .onClick(() => {
                MyDialogParams.close(this.params);
                this.params.btnOKClick?.(this.curDate);
              })
              .visibility(this.params.btnOK!.length > 0 ? Visibility.Visible : Visibility.Hidden)
          }
        }.constraintSize({ minWidth: 16 })
      }.margin({ top: 5 })

      Text().width("100%").height(1).backgroundColor(line)
    }
  }

  @Builder
  buildBody() {
    Column() {
      this.builderTitleBar()
      Column() {
        Row() {
          if (this.params.type != "Time") {
            DatePicker({ start: this.params.minDate as Date, end: this.params.maxDate as Date, selected: this.curDate })
              // .onDateChange((value: Date) => {
              //   this.curDate.setTime(value.getTime());
              //   if (this.params.onChange) this.params.onChange(this.curDate);
              // })
              .onChange((value) => {
                this.curDate.setFullYear(value.year ?? 0, value.month, value.day);
                if (this.params.onChange) this.params.onChange(this.curDate);
              })
              .layoutWeight(2)
          }
          if (this.params.type != "Date") {
            TimePicker({ selected: this.curDate }).useMilitaryTime(true).onChange((value: TimePickerResult) => {
              this.curDate.setHours(value.hour, value.minute);
              if (this.params.onChange) this.params.onChange(this.curDate);
            }).layoutWeight(1)
          }
        }.padding({ left: 16, right: 16 })
      }.justifyContent(FlexAlign.Center).margin({ top: 16, bottom: 16 })
    }
    .backgroundColor(Color.White)
    .width("100%")
    .justifyContent(FlexAlign.Center)
    .onClick(() => {

    })
  }

  build() {
    Column() {
      Column() {
        this.buildBody();
      }.justifyContent(FlexAlign.End).height("100%")
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .width("100%")
    .height("100%")
    .onClick(() => {
      if (this.params.autoCancel) {
        MyDialogParams.close(this.params);
        this.params.cancel?.();
      }
    })
  }
}

@Component
struct MyDialogComponentBuilder {
  private controller: CustomDialogController | null = null;
  params!: MyDialogParams;

  aboutToAppear() {
    let defaultMarginForDialog: Offset = { dx: 0, dy: 18 };

    this.params.autoCancel ??= true;
    let type: MyDialogType = MyDialogParams.getDialogType(this.params);
    if (type === "alert") {
      this.controller = new CustomDialogController({
        builder: AlertDialogBuilder({ params: this.params as AlertParams }),
        cancel: () => {
          MyDialogParams.removeFromStack(this.params);
          this.params.cancel?.();
        },
        autoCancel: this.params.autoCancel,
        customStyle: true,
        offset: defaultMarginForDialog,
      });
    } else if (type === "progress") {
      this.controller = new CustomDialogController({
        builder: ProgressDialogBuilder({ params: this.params as ProgressParams }),
        cancel: () => {
          MyDialogParams.removeFromStack(this.params);
          this.params.cancel?.();
        },
        autoCancel: this.params.autoCancel,
        customStyle: true,
        offset: defaultMarginForDialog,
      });
    } else if (type === "pullUpButton") {
      this.controller = new CustomDialogController({
        builder: PullUpButtonDialogBuilder({ params: this.params as PullUpButtonParams }),
        cancel: () => {
          MyDialogParams.removeFromStack(this.params);
          this.params.cancel?.();
        },
        autoCancel: this.params.autoCancel,
        customStyle: true,
        offset: defaultMarginForDialog,
      });
    } else if (type === "datetime") {
      this.controller = new CustomDialogController({
        builder: DateTimeDialogBuilder({ params: this.params as DateTimeParams }),
        cancel: () => {
          MyDialogParams.removeFromStack(this.params);
          this.params.cancel?.();
        },
        autoCancel: this.params.autoCancel,
        customStyle: true,
        offset: defaultMarginForDialog,
      });
    }

    if (this.controller) {
      MyDialogParams.setCloseFunc(this.params, () => {
        this.controller?.close();
      });
      this.controller.open();
    }
  }

  build() {

  }
}


/**
 * * [dialog] 为必传参数
 */
@Component
export struct MyDialogComponent {
  public dialog?: MyDialog;
  adapter: BaseAdapter<MyDialogParams> = new BaseAdapter([], true);

  aboutToAppear() {
    if (!this.dialog) throw new Error("MyDialogComponent 需要传入参数 [dialog],才可以正常使用")
    MyObject.setAttr(this.dialog, "_open", (params: MyDialogParams) => {
      MyDialogParams.setRemoveFromStackFunc(params, () => {
        this.adapter.removeData(params);
      });
      this.adapter.addData(params);
    });
    MyObject.setAttr(this.dialog, "_close", (params: MyDialogParams, closeSlowly: boolean = false) => {
      MyDialogParams.close(params);
    });
  }

  build() {
    Column() {
      List() {
        LazyForEach(this.adapter, (itemData: MyDialogParams, index) => {
          ListItem() {
            MyDialogComponentBuilder({ params: itemData })
          }
        }, (itemData: MyDialogParams, index) => {
          return this.adapter.getKeyGenerator(itemData, index);
        })
      }.listDirection(Axis.Horizontal).width(1)
    }.width(0).height(0)
  }
}

@Entry
@Component
struct Test {
  dialog = new MyDialog();
  count: number = 0;

  build() {
    Column({ space: 16 }) {
      MyDialogComponent({ dialog: this.dialog });
      Button('警告框').onClick(() => {
        this.dialog.alert({ message: "哈哈哈", autoCancel: false });
      })
      Button('下拉选择').onClick(() => {
        // let pullUp = new PullUpButtonParams();
        // pullUp.btnList = ["1", "1", "1", "1",];
        // pullUp.btnCancel = "关闭";
        // this.dialog.open("pullUpButton", pullUp);

        this.dialog.pullUpButton({ btnList: ["1", "1", "1", "1",], btnCancel: "关闭" })
      })
      Button('日期选择').onClick(() => {
        let datetime = new DateTimeParams();
        datetime.btnOK = "确定";
        this.dialog.open("datetime", datetime);

      })
    }.width("100%")
  }
}

MyDialog.ets

import promptAction from '@ohos.promptAction';

export type typeAll = Object | Function | string | number | null | undefined;

export class MyObject {
  static setAttr(params: Object, key: string, value: typeAll) {
    if (params) (params as Record<string, typeAll>)[key] = value;
  }

  static getAttr(params: Object, key: string): typeAll {
    if (params) return (params as Record<string, typeAll>)[key];
    return undefined;
  }
}

/**
 * 对话框类型
 */
export type MyDialogType = "alert" | "progress" | "pullUpButton" | "datetime";

export class MyDialogParams {
  /**
   * 是否自动关闭
   */
  autoCancel?: boolean = true;
  /**
   * 自动关闭时的回调
   */
  cancel?: () => void;
  dialog?: MyDialog;

  /**
   * 获取对话框类型
   * @param defaultType 默认为 "alert"
   */
  static getDialogType(params: MyDialogParams, defaultType: MyDialogType = "alert"): MyDialogType {
    return MyObject.getAttr(params, "_type") as MyDialogType ?? defaultType;
  }

  static setDialogType(params: MyDialogParams, type: MyDialogType) {
    MyObject.setAttr(params, "_type", type);
  }

  /**
   * 从当前堆栈中移除
   */
  static removeFromStack(params: MyDialogParams) {
    (MyObject.getAttr(params, "_removeParams") as Function)?.();
  }

  static setRemoveFromStackFunc(params: MyDialogParams, removeParams: () => void) {
    MyObject.setAttr(params, "_removeParams", removeParams);
  }

  /**
   * 关闭弹窗
   */
  static close(params: MyDialogParams) {
    (MyObject.getAttr(params, "_close") as Function)?.();
  }

  static setCloseFunc(params: MyDialogParams, close: () => void) {
    MyObject.setAttr(params, "_close", () => {
      MyDialogParams.removeFromStack(params);
      close?.();
    });
  }
}

/**
 * 提示框
 */
export class AlertParams extends MyDialogParams {
  title?: string = "";
  message: string = "";
  btnOK?: string = "确定";
  btnOKClick?: () => void;
  btnCancel?: string = "";
  btnCancelClick?: () => void;
}

/**
 * 进度框(progress 有值,就开启进度条)
 */
export class ProgressParams extends MyDialogParams {
  message?: string;
  progress?: number;
  updateProgress?: (progress: number, message?: string) => void;
}

/**
 * 底部弹出按钮框
 */
export class PullUpButtonParams extends MyDialogParams {
  btnList: string[] = [];
  btnCancel?: string;
  btnClick?: (btnName: string, index?: number) => void;
}

export class DateTimeParams extends MyDialogParams {
  selectedDate?: Date;
  type: "DateTime" | "Date" | "Time" = "Date";
  title?: string;
  minDate?: string | Date;
  maxDate?: string | Date;
  btnOK?: string;
  btnOKClick?: (selectedDate: Date) => void;
  btnCancel?: string;
  btnCancelClick?: () => void;
  onChange?: (selectedDate: Date) => void;
}

export class OverlayParams extends MyDialogParams {
  message?: string;
  showTime?: number = 5000;
}

/**
 * * 1. close closeSlowly 暂时无法使用,等以后能用的时候,再来调整
 */
export class MyDialog {
  alert(params: AlertParams) {
    this.open("alert", params);
    return params;
  }

  progress(params: ProgressParams) {
    this.open("progress", params);
    return params;
  }

  pullUpButton(params: PullUpButtonParams) {
    if (params && params.btnList.length > 0) {
      this.open("pullUpButton", params);
    }
    return params;
  }

  datetime(params: DateTimeParams) {
    this.open("datetime", params);
    return params;
  }

  open(type: MyDialogType, params: MyDialogParams) {
    params.dialog = this;
    MyObject.setAttr(params, "_type", type);
    (MyObject.getAttr(this, "_open") as Function)?.(params);
  }

  close(params: MyDialogParams, closeSlowly: boolean = false) {
    // 为了防止操作过快的情况,所以延迟执行
    setTimeout(() => {
      (MyObject.getAttr(this, "_close") as Function)?.(params, closeSlowly);
    }, 10);
  }

  toast(message: string, duration?: number, bottom?: string | number) {
    promptAction.showToast({ message: message, duration: duration, bottom: bottom, })
  }

  static showToast(message: string, duration?: number, bottom?: string | number) {
    promptAction.showToast({ message: message, duration: duration, bottom: bottom, })
  }

  showError(message: string, btnOKClick?: () => void, title: string = "提示", btnOK: string = "确定") {
    if (message && message.length > 0) this.alert({ title: title, message: message, btnOK: btnOK, btnOKClick: btnOKClick, })
  }

  showErrorCannotAutoClose(message: string, btnOKClick?: () => void, title: string = "提示", btnOK: string = "确定") {
    if (message && message.length > 0) this.alert({
      autoCancel: false,
      title: title,
      message: message,
      btnOK: btnOK,
      btnOKClick: btnOKClick,
    })
  }

  showAlertDialog(msg: string, btnOKClick: () => void, btnCancelClick?: () => void, autoClose: boolean = true) {
    this.alert({
      autoCancel: autoClose,
      title: "提示",
      message: msg,
      btnOK: "确定",
      btnOKClick: btnOKClick,
      btnCancel: "取消",
      btnCancelClick: btnCancelClick,
    });
  }

  showAlertDialogCustomize(msg: string, title: string = "提示", btnOK: string = "确定", btnOKClick: () => void, btnCancel?: string, btnCancelClick?: () => void, autoClose: boolean = true): void {
    this.alert({
      autoCancel: autoClose,
      title: title,
      message: msg,
      btnOK: btnOK,
      btnOKClick: btnOKClick,
      btnCancel: btnCancel,
      btnCancelClick: btnCancelClick,
    });
  }
}

MyButton.ets


@Component
export struct MyButton {
  text: string = "";
  click?: () => void;
  styleForDisable: number = 0;
  isEnable: boolean = true;
  buttonHeight: number | string | null = 44;
  buttonWidth: number | string | null = "100%";
  private isFocus: boolean = false;
  @State mFontColor: number | null = 0;
  @State mBackgroundColor: number | null = 0;
  @State mBorderColor: number | null = 0;
  readonly colorForButton: (number | null)[][] = [[0xffffffff, 0xffE5431B, null], [0xffffffff, 0xffFF8A8A, null], [0xffffffff, 0xffFFEEEE, null]];

  aboutToAppear() {
    this.refreshColor();
  }

  refreshColor() {
    let colorIndex = 0;
    if (this.isEnable) {
      if (this.isFocus) colorIndex = 1;
    } else {
      if (this.styleForDisable == 1) colorIndex = 0;
      else colorIndex = 2;
    }

    let fontColor = this.colorForButton[colorIndex][0];
    let backgroundColor = this.colorForButton[colorIndex][1];
    let borderColor = this.colorForButton[colorIndex][2];
    if (!this.isEnable && this.styleForDisable == 1) {
      if (backgroundColor != null) backgroundColor = ((((backgroundColor & 0xff000000) >>> 1) & 0xff000000) | (backgroundColor & 0xffffff));
      if (borderColor != null) borderColor = ((((borderColor & 0xff000000) >>> 1) & 0xff000000) | (borderColor & 0xffffff));
    }
    this.mFontColor = fontColor;
    this.mBackgroundColor = backgroundColor;
    this.mBorderColor = borderColor;
  }

  build() {
    Text(this.text)
      .fontColor(this.mFontColor)
      .fontSize(16)
      .maxLines(2)
      .textOverflow({ overflow: TextOverflow.Ellipsis })
      .width(this.buttonWidth)
      .height(this.buttonHeight)
      .backgroundColor(this.mBackgroundColor ?? null)
      .padding({ left: 12, right: 12 })
      .borderRadius(5)
      .borderColor(this.mBorderColor)
      .borderWidth(this.mBorderColor ? 1 : 0)
      .textAlign(TextAlign.Center)
      .onClick(() => {
        if (this.isEnable && this.click) this.click();
      })
      .onTouch(this.isEnable ? (event) => {
        if (event.type == TouchType.Down) {
          this.isFocus = true;
          this.refreshColor();
        } else if (event.type == TouchType.Up || event.type == TouchType.Cancel) {
          this.isFocus = false;
          this.refreshColor();
        }
      } : null)
  }
}

MyBaseAdapter.ets


export class BaseAdapter<T> implements IDataSource {
  private listeners: DataChangeListener[] = new Array<DataChangeListener>();
  private _dataList: T[];
  private _keyList: (string | null)[] = [];
  private cacheKey: boolean;
  private keyIndex: number = 0;

  constructor(dataList?: T[], cacheKey: boolean = false) {
    this._dataList = dataList ?? [];
    this.cacheKey = cacheKey;
    if (this.cacheKey) this._keyList = new Array(this._dataList.length);
  }

  public get dataList(): T[] {
    return this._dataList;
  }

  public set dataList(dataList: T[]) {
    this._dataList = dataList;
    if (this.cacheKey) this._keyList = new Array(this._dataList.length);
  }

  public refreshDatas(dataList: T[]) {
    this._dataList = dataList;
    if (this.cacheKey) this._keyList = new Array(this._dataList.length);
    this.notifyDataReload();
  }

  // 如果数据没有主键的时候,请使用这种方式来生成
  public getKeyGenerator(t: T, index: number): string {
    if (this.cacheKey) {
      let key: string | null = this._keyList[index];
      if (typeof key === 'string') return key;
      key = this.newKey();
      this._keyList[index] = key;
      return key;
    }
    return this.newKey();
  }

  private newKey(): string {
    return (this.keyIndex++).toString();
  }

  public getCount(): number {
    return this._dataList.length;
  }

  public refreshData(t: T) {
    let index = this._dataList.indexOf(t);
    if (index >= 0) {
      if (this.cacheKey) this._keyList[index] = this.newKey();
      this.notifyDataChange(index);
    }
  }

  public addData(t: T): void {
    this._dataList.push(t);
    if (this.cacheKey) this._keyList.push(null);
    this.notifyDataReload();
  }

  public addDatas(ts: T[]): void {
    if (ts && ts.length > 0) {
      if (ts.length == 1) {
        this._dataList.push(ts[0]);
        if (this.cacheKey) this._keyList.push(null);
        this.notifyDataReload();
      } else {
        for (let data of ts) {
          this._dataList.push(data);
          if (this.cacheKey) this._keyList.push(null);
        }
        this.notifyDataReload();
      }
    }
  }

  public insetData(index: number, ...ts: T[]) {
    if (ts && ts.length > 0 && index >= 0 && index <= ts.length) {
      for (let data of ts) {
        this._dataList.splice(index, 0, data);
        if (this.cacheKey) this._keyList.splice(index, 0, null);
        index++;
      }
      this.notifyDataReload();
    }
  }

  removeDataByIndex(index: number) {
    if (index >= 0 && index < this._dataList.length) {
      this._dataList.splice(index, 1);
      if (this.cacheKey) this._keyList.splice(index, 1);
      this.notifyDataReload();
    }
  }

  removeData(t: T) {
    let index = this._dataList.indexOf(t);
    if (index >= 0) {
      this._dataList.splice(index, 1);
      if (this.cacheKey) this._keyList.splice(index, 1);
      this.notifyDataReload();
    }
  }

  removeDatas(ts: T[]) {
    if (ts && ts.length > 0) {
      if (ts.length == 1) {
        let index = this._dataList.indexOf(ts[0]);
        if (index >= 0) {
          this._dataList.splice(index, 1);
          if (this.cacheKey) this._keyList.splice(index, 1);
          this.notifyDataReload();
        }
      } else {
        for (let data of ts) {
          let index = this._dataList.indexOf(data);
          if (index >= 0) {
            this._dataList.splice(index, 1);
            if (this.cacheKey) this._keyList.splice(index, 1);
          }
        }
        this.notifyDataReload();
      }
    }
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      this.listeners.splice(pos, 1);
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    })
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    })
  }

  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    })
  }

  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    })
  }

  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    })
  }

  public totalCount(): number {
    return this._dataList.length;
  }

  public getData(index: number): T {
    return this._dataList[index];
  }

  public getDataIndex(t: T) {
    return this._dataList.indexOf(t);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值