3

本周正式接手了新项目,目前感觉主要难度就体现在——找不到代码,找不到对应接口,项目主体结构与之前接触过的有较大差距。
还有就是由于这个项目并不是只由我们来写,并且是最新的版本,所以这就不可避免的会遇到其他人创造出来的bug,比如说我们可能会遇到前些天我们接到的任务是修改XX界面的一些东西,到了今天fetch完最新代码再一看发现这个页面直接就进不去了,在这上面耗费的时间往往短不了。甚至可能一整晚的时间全用来启动项目和避免引发现有的bug。

首先要解决的就是弹窗问题,期初由于新项目代码确实比较多并且项目启动上也遇到了些问题,并且新项目前台用到的主体样式tethys在之前也都用过,于是就在项目启动期间在本地试试官方给出的弹窗。
在之前项目中弹窗都是以子组件V层中直接使用的形式来实现的,或者说只是用来进行点击确定的弹窗如下:
image.png
但是很明显这些并不适用,我们当前需要的是在父组件C层中可以直接调用子组件进行弹窗显示,所以就尝试着按官方给出的教程来测试。

首先在父组件中我们要进行如下声明:

export class FatherComponent extends mixinUnsubscribe(MixinBase)  {

unsubscribe: () => void; 
constructor(
              private dialog: ThyDialog,
              private renderer: Renderer2
  ) {
    super();
     dialog
      .afterOpened()
      .pipe(takeUntil(this.ngUnsubscribe$))
      .subscribe(dialog => {
        console.log(dialog);
      });
    this.unsubscribe = renderer.listen(document, 'keydown', (event: KeyboardEvent) => {
      const isK = (event.ctrlKey || event.metaKey) && event.keyCode === keycodes.K;
      if (!this.hasShowDialog && isK) {
        this.openComponentDialog();
      }
    });
  }

hasShowDialog = false;
  public config: ThyDialogConfig = {
    size: ThyDialogSizes.md,
    hasBackdrop: true,
    backdropClosable: true,
    closeOnNavigation: true,
    hostClass: ['test-dialog-content', 'another-test-dialog-content']
  };
  public layoutConfig = {
    align: 'left',
    divider: true
  };
  openComponentDialog() {
    this.hasShowDialog = true;
    const dialogRef = this.dialog.open(
      ThyBAsicComponent,
      Object.assign(
        {
          initialState: {
            data: `This is Pass Data`,
            align: this.layoutConfig.align,
            divider: this.layoutConfig.divider,
            testData: "这是测试数据"
          },
          canClose: () => {
            this.dialog.confirm({
              title: '确认归档',
              content: '确认要归档选中的6项任务吗?',
              footerAlign: 'right',
              okType: 'primary',
              okText: '确认归档',
              cancelText: '取消归档',
              onOk: () => {
                dialogRef.close(null, true);
              }
            });
            return false;
          }
        },
        this.config
      )
    );
    dialogRef.keydownEvents().subscribe(event => {
      console.log(`Dialog keydownEvents: ${event}`);
    });
    dialogRef.afterClosed().subscribe(result => {
      this.hasShowDialog = false;
      console.log(`Dialog afterClosed result: ${result}`);
    });

ngOnDestroy() {
        super.ngOnDestroy();
        if (this.unsubscribe) {
            this.unsubscribe();
        }
    }
  }

虽然给出了示例代码,但是并没有给出相应的注释,我们可以发现里面有很多写法我们并没有接触过,接下来讲一下具体改怎么使用.

先讲一下这里面用到的RXjs操作符——takeUntil
其具体过程可由下面的图来解释
image.png
具体使用:
source相当于图中的observible1,clicks相当于图中的observible2.

    const source = interval(1000);
    const clicks = fromEvent(document, 'click');
    const result = source.pipe(takeUntil(clicks));
    result.subscribe(x => console.log(x));
    clicks.subscribe(
      () => { console.log('点击,触发click')}
    )

其表达的就是我们每过一秒让source发出一个值然后进行订阅输出,当我们触发clicks时停止订阅输出。
image.png

然后就是为什么要继承mixinUnsubscribe(MixinBase)
搜索资料后发现这是为了在组件销毁时自动取消订阅,比如他的官方文档是这样给的

dialog
      .afterOpened()
      .pipe(takeUntil(this.ngUnsubscribe$))
      .subscribe(dialog => {
        console.log(dialog);
      });

结合之前所说,就是mixinUnsubscribe(MixinBase)提供了变量ngUnsubscribe来检测组件销毁,然后当组件销毁时自动取消订阅。

除了这些我们想做的无非就是——如何展示子组件,如何向子组件传值,如何获取子组件的值。
官方示例代码中给出了openComponentDialog()方法来展示子组件,我们直接在C层进行调用即可比如在完成某些操作后显示。
但是官方在下面这个方法中调用了展示子组件方法。

constructor( private dialog: ThyDialog,
              private renderer: Renderer2
  ){    
    this.unsubscribe = renderer.listen(document, 'keydown', (event: KeyboardEvent) => {
      const isK = (event.ctrlKey || event.metaKey) && event.keyCode === keycodes.K;
      if (!this.hasShowDialog && isK) {
        this.openComponentDialog();
      }
    });
}

并且Renderer2是angular自带的类,搜索后很容易发现这是用来干什么的。
查询angular官方文档后发现其作用主要为:获取DOM元素,监听DOM事件,修改DOM元素等。
比如上面的方法就是可以让我们在窗口中按下ctrl/meta+k时自动弹出子组件。

 openComponentDialog() {
    this.hasShowDialog = true;
    const dialogRef = this.dialog.open(
      ThyBAsicComponent,
      Object.assign(
        {
          initialState: {
            data: `This is Pass Data`,
            align: this.layoutConfig.align,
            divider: this.layoutConfig.divider,
            testData: "这是测试数据"
          },
          canClose: () => {
            this.dialog.confirm({
              title: '确认归档',
              content: '确认要归档选中的6项任务吗?',
              footerAlign: 'right',
              okType: 'primary',
              okText: '确认归档',
              cancelText: '取消归档',
              onOk: () => {
                dialogRef.close(null, true);
              }
            });
            return false;
          }
        },
        this.config
      )
    );
}

至于剩下的操作就很容易理解了,并且在其官方文档的Api中也有写各个参数的具体含义。
我们主要需要的还是initialState,我们可以通过此参数来给子组件赋值,而我们要做的仅仅是在子组件中声明即可:

  align!: ThyDialogFooterAlign;
  divider!: ThyDialogFooterAlign;
  testData!: string;
  data!: string;

他们会在弹出组件的变量会自动赋值,在 ngOnInit 生命周期钩子可以获取到,构造函数获取不到。
如果我们想获取子组件中的信息,可直接通过dialogRef来获取,有关其相关方法(如当子组件关闭/开启时想要父组件触发回调函数等)也可在官方文档中找到,在此就不多赘述。
image.png

后来又去项目中找到了以往的弹窗代码书写方式发现与上述过程基本一致,再去理解起来就简单了很多。

总结:本周正式接受了新项目由于经验不足再加上没有良好的提交习惯(由于写完代码没有及时commit导致代码丢失)浪费了不少的时间,在习惯这方面还有很多要学习的地方。


李明
441 声望19 粉丝