• Angular 学习笔记 (组件沟通的思考)


    组件指令间经常需要沟通 

    我们知道的方式有 

    input

    output

    service

    inject

    viewchild

    contentchild

    templateRef

    template variable

    但是哪种情况下用哪种呢 ? 

    思考 1, input -> input -> input 这种一层层传进去是否是 ok 的 ? 

    <mat-calendar cdkTrapFocus
        [id]="datepicker.id"
        [ngClass]="datepicker.panelClass"
        [startAt]="datepicker.startAt"
        [startView]="datepicker.startView"
        [minDate]="datepicker._minDate"
        [maxDate]="datepicker._maxDate"
        [dateFilter]="datepicker._dateFilter"
        [headerComponent]="datepicker.calendarHeaderComponent"
        [selected]="datepicker._selected"
        [dateClass]="datepicker.dateClass"
        [@fadeInCalendar]="'enter'"
        (selectedChange)="datepicker.select($event)"
        (yearSelected)="datepicker._selectYear($event)"
        (monthSelected)="datepicker._selectMonth($event)"
        (_userSelection)="datepicker.close()">
    </mat-calendar>

    看看人家 material datepicker 

    datepicker 指令通过 overlay 创建 datepickerContent 组件, 然后 this._popupComponentRef.instance.datepicker = this; 把自己传进去, 在把 datepicker input 一个个放入 mat-calendar input (上图)

      private _openAsPopup(): void {
        if (!this._calendarPortal) {
          this._calendarPortal = new ComponentPortal<MatDatepickerContent<D>>(MatDatepickerContent,
                                                                              this._viewContainerRef);
        }
    
        if (!this._popupRef) {
          this._createPopup();
        }
    
        if (!this._popupRef.hasAttached()) {
          this._popupComponentRef = this._popupRef.attach(this._calendarPortal);
          this._popupComponentRef.instance.datepicker = this;
          this._setColor();
    
          // Update the position once the calendar has rendered.
          this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
            this._popupRef.updatePosition();
          });
        }
      }

    所以你说 input -> input 又如何呢 ?

    我个人觉得 wrap component 就一层一层传咯, 无所谓的啦. 

    思考 2 : output vs input callback function 

    <abc (submit)="submit($event)" [submitFn]="submitFn"  ></abc>

    output 是广播的概念, 广播的缺点就是没有的写 callback, 

    假设我想封装一个 submit loading, submit 由外部负责, 那么我写一个 output 我就无法知道什么时候 loading 结束, 除非外部又 input 一个 submit 结束进来. 

    如果是 input + callback 就容易. 

    但是 input + callback 也有问题就是不能任意输入变量

    比如 (submit)="submit($event, index)" 可以很简单的传入 ngFor 的 index, 而 submitFn 就不行了.

    广播后有一种方式可以跟外部沟通就是通过 event 

    比如 event.preventDefault() 就是一个通讯. 

    我们可以做一个 event.submitDone() 来通知内部, submit 结束了,让 loading 关闭. 

    但是这种方式还是有点诡异, 毕竟广播的概念是可以多个人监听. 这个 submitDone 视乎指定了一个监听者在使用.. 

    最后我也不知道如何是好啦. 

    思考 3 : ng-content vs input ng-template 

    content 很直观, 但是缺点也很恐怖, 就是只能一层. 你 wrap 一个 component 基本上 content 就废了.

    怎么说废了呢, 因为 contentchild 会获取不了 

    https://github.com/angular/angular/issues/20810

    https://github.com/angular/angular/issues/8563

    看看 material table 

    https://github.com/angular/material2/issues/6980

    如果你 wrap 了 material table, 你需要通过 viewchild 找到 mat table 然后调用 api 来把 content 输入进去. 是不是麻烦 ? 

    对比 ng-template 或者 dynamic component 就不同了. 通过 input 输入, 就可以传到底层, 比如 material datepicker 的 header component.

    此外它们还有很大的不同在于使用.

    看看 material select , material option group , material option 的配搭. 

    如果用 template 实现就很不同了. 

    这个例子中 option 是外部负责 ngfor 创建然后传入的, template 要实现的话. 你只能传入 items + template 内部实现 ngfor 渲染 template.

    思考 4:  template variable 

    <form class="example-form">
      <mat-form-field class="example-full-width">
        <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
        <mat-autocomplete #auto="matAutocomplete">
          <mat-option *ngFor="let option of options" [value]="option">
            {{option}}
          </mat-option>
        </mat-autocomplete>
      </mat-form-field>
    </form>

    注意 mat-autocomplete 和 input 是如何连上的吗 ? 

    通过一个指令 [matAutocomplete] + template variable 

    如果你熟悉面向对象编程, 然后把 component 想象成 new ComponentClass 得到的对象.

    那么你会发现模板之间就是 对象与对象的互相方法调用,修改属性而已. 

    所以当你 new 了很多 component 后,你要他们一起工作,你就需要让它们互相依赖. 

    比如 

    let input = new Input();

    let autoDir = new AutoDir();

    let auto = new Auto();

    autoDir.auto = auto;

    autoDir.input = input;

    autoDir.watchInputThenOpenAuto();

    watchInputThenOpenAuto(){ 

      this.input.change(() => {  this.auto.open().filterBy(this.input.value);  });

    }

  • 相关阅读:
    第 16 章 CSS 盒模型[下]
    第 16 章 CSS 盒模型[上]
    第 15 章 CSS 文本样式[下]
    第 15 章 CSS 文本样式[上]
    第 14 章 CSS 颜色与度量单位
    第 13 章 CSS 选择器[上]
    第 12 章 CSS 入门
    关于springboot上传文件报错:The temporary upload location ***is not valid
    Java Enum枚举 遍历判断 四种方式(包括 Lambda 表达式过滤)
    git命令-切换分支
  • 原文地址:https://www.cnblogs.com/keatkeat/p/10181499.html
Copyright © 2020-2023  润新知