欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Angular實(shí)踐之將Input與Lifecycle轉(zhuǎn)換成流示例詳解

 更新時(shí)間:2023年02月17日 14:45:00   作者:Lian?Shenghua  
這篇文章主要為大家介紹了Angular實(shí)踐之將Input與Lifecycle轉(zhuǎn)換成流示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

將 Input 和生命周期函數(shù)轉(zhuǎn)換成流

在 Angular 中一直有一個(gè)期待,就是希望能夠?qū)?Input 和生命周期函數(shù)轉(zhuǎn)換成流,實(shí)際上我們可以通過(guò)比較簡(jiǎn)單的方式實(shí)現(xiàn),比如說(shuō):

class NameComponent {
  @Input() name: string;
}

我們要實(shí)現(xiàn)一個(gè) input 為 name, output 為 hello name 的簡(jiǎn)單 component。如果將 input 看成是一個(gè)流的話,就會(huì)比較容易實(shí)現(xiàn)。常見(jiàn)的流轉(zhuǎn)換方式是通過(guò) set 方法實(shí)現(xiàn):

class NameComponent {
  private name$ = new Subject(1);
  private _name: string;
  @Input() set name(val: string) {
    this.name$.next(val);
    this._name = val;
  }
  get name() {
    return this._name;
  }
  @Output() helloName = this.name$.pipe(
    map(name => `hello ${name}`),
  );
}

這樣寫(xiě)是可以,不過(guò)你也看出來(lái)了,有一個(gè)問(wèn)題,就是麻煩。

對(duì)于生命周期函數(shù),我們也有類(lèi)似的需求。比如說(shuō),我們經(jīng)常需要在 Angular 銷(xiāo)毀的時(shí)候,unsubscribe 所有的 subscription。

class NameComponent implements OnDestroy {
  private destory$ = new Subject<void>();
  ngOnDestroy(): void {
    destory$.next();
    destory$.complete();
  }
}

如果需要使用其他的生命周期函數(shù)的話,每個(gè)函數(shù)都需要這樣手動(dòng)調(diào)用一次。

思路

如果回到 input 的問(wèn)題的話,我們知道,獲取 input 的變化,除了 set 方法,還有 ngOnChanges 函數(shù)。我們很容易想到一個(gè)思路:

  • 將 ngOnChanges 轉(zhuǎn)換成一個(gè) stream, onChanges$
  • 通過(guò) onChanges$ map 成 input stream
private onChanges$ = new Subject<SimpleChanges>();
@Input() name: string;
name$ = this.onChanges$.pipe(
  switchMap(simpleChanges => {
    if ('name' in simpleChanges) {
      return of(simpleChanges?.name?.currentValue);
    }
    return EMPTY;
  }),
)
ngOnChanges(simpleChanges: SimpleChanges) {
  this.onChanges$.next(simpleChanges);
}

當(dāng)然,ngOnChanges 只會(huì)在 input 變化的時(shí)候觸發(fā),所以我們還需要加上 init 以后的初始值。(當(dāng)然,我們也要將 afterViewInit 轉(zhuǎn)換成 stream)

name$ = afterViewInit$.pipe(
  take(1),
  map(() => this.name),
  switchMap(value => this.onChanges$.pipe(
    startWith(value),
    if ('name' in simpleChanges) {
      return of(simpleChanges?.name?.currentValue);
    }
    return EMPTY;
  )),
) 

抽離成一個(gè)方法

很明顯,如果 input 比較多的話,這樣寫(xiě)就比較冗余了。很容易想到我們可以把它抽離成一個(gè)方法。

export function getMappedPropsChangesWithLifeCycle<T, P extends (keyof T & string)>(
  target: T,
  propName: P,
  onChanges$: Observable<SimpleChanges>,
  afterViewInit$: Observable<void>) {
  if (!onChanges$) {
    return EMPTY;
  }
  if (!afterViewInit$) {
    return EMPTY;
  }
  return afterViewInit$.pipe(
    take(1),
    map(() => target?.[propName]),
    switchMap(value => target.onChanges$.pipe(
      startWith(value),
      if (propName in simpleChanges) {
        return of(simpleChanges?.[propName]?.currentValue);
      }
      return EMPTY;
    ))
  ) 
}

看到這里,你可能很容易就想到了,我們可以把這個(gè)方法變成一個(gè) decorator,這樣看起來(lái)就簡(jiǎn)潔多了。比如我們定義一個(gè)叫做 InputMapper 的裝飾器:

export function InputMapper(inputName: string) {
  return function (target: object, propertyKey: string) {
    const instancePropertyKey = Symbol(propertyKey);
    Object.defineProperty(target, propertyKey, {
      get: function () {
        if (!this[instancePropertyKey]) {
          this[instancePropertyKey] = getMappedPropsChangesWithLifeCycle(this, inputName, this['onChanges$']!, this['afterViewInit$']!);
        }
        return this[instancePropertyKey];
      }
    });
  };
}

值得注意的是,因?yàn)?target 會(huì)是 component instance 的 proto,會(huì)被所有的 instance 共享,所以我們?cè)诙x變量的時(shí)候,可以通過(guò) defineProperty 中的 get 函數(shù)將變量定義到 this 上。這樣 component instance 在調(diào)用的時(shí)候就可以成功將內(nèi)容 apply 到 instance 而費(fèi) component class 的 prototype 上。

當(dāng)然,使用的時(shí)候就會(huì)方便很多了:

class NameComponent {
  private onChanges$ = new Subject<SimpleChanges>();
  private afterViewInit$ = new Subject<void>();
  @Input() name: string;
  @InputMapper('name') name$!: Observable<string>;
  ngOnChanges() {
  ...
  } 
  ngAfterViewInit() {
  ...
  }
}

當(dāng)然,因?yàn)閷?duì)于生命周期函數(shù),也是重復(fù)性工作,我們很容易想到,是否能夠也能通過(guò)裝飾器實(shí)現(xiàn)。

重寫(xiě)生命周期函數(shù)

我們只需要重寫(xiě)生命周期函數(shù)就可以巧妙的實(shí)現(xiàn)了:

  • 用類(lèi)似的方法,在 this 定義 subject
  • 保存原有的函數(shù)
  • 通過(guò) prototype 重寫(xiě)原來(lái)的函數(shù),調(diào)用 subject.next。
  • 可以參考這里的實(shí)現(xiàn): Angular2+ Observable Life-cycle Events (induro.io)
export function LifeCycleStream(lifeCycleMethodName: LifeCycleMethodName) {
  return (target: object, propertyKey: string) => {
    const originalLifeCycleMethod = target.constructor.prototype[lifeCycleMethodName];
    const instanceSubjectKey = Symbol(propertyKey);
    Object.defineProperty(target, propertyKey, {
      get: function () {
        if (!this[instanceSubjectKey]) {
          this[instanceSubjectKey] = new ReplaySubject(1);
        }
        return this[instanceSubjectKey].asObservable();
      }
    });
    target.constructor.prototype[lifeCycleMethodName] = function () {
      if (this[instanceSubjectKey]) {
        this[instanceSubjectKey].next.call(this[instanceSubjectKey], arguments[0]);
      }
      if (originalLifeCycleMethod && typeof originalLifeCycleMethod === 'function') {
        originalLifeCycleMethod.apply(this, arguments);
      }
    };
  }
}

那么我們可以將之前工作簡(jiǎn)化為:

class NameComponent {
  @LifeCycleStream('ngOnChanges') onChanges$: Observable<SimpleChanges>;
  @LifeCycleStream('ngAfterViewInit') ngAfterViewInit$: Observable<void>;
  @Input() name: string;
  @InputMapper('name') name$!: Observable<string>;
  ...
  ...
}

然后,因?yàn)槲覀円呀?jīng)實(shí)現(xiàn)了 InputMapper,那么很容易想到,有沒(méi)有可能把 onChanges$afterViewInit$ 放進(jìn) InputMapper,這樣我們就可以減少重復(fù)的調(diào)用了。我們可以把 LifeCycleStream 中的主體邏輯抽離成一個(gè)方法:applyLifeCycleObservable,然后在 InputMapper 調(diào)用就可以了:

if (!('afterViewInit$' in target)) {
  applyLifeCycleObservable('ngAfterViewInit', target, 'afterViewInit$');
}
if (!('onChanges$' in target)) {
  applyLifeCycleObservable('ngOnChanges', target, 'onChanges$');
}

當(dāng)然,我們?cè)谡{(diào)用前需要檢查這個(gè) stream 是否已經(jīng)存在。注意,這里不要直接調(diào)用 target['ngAfterViewInit'], 因?yàn)槲覀冎皩?xiě)了 get 函數(shù)??梢运伎枷聻槭裁?。(防止將 ngAfterViewInit apply 到 target 上去)

最后,我們來(lái)看一下最終的代碼:

class NameComponent {
  @Input() name: string;
  @InputMapper('name') name$!: Observable<string>;
}

這樣,既沒(méi)有破壞已有的 angular input,又能夠很快的實(shí)現(xiàn),input to stream 的轉(zhuǎn)換,還是比較方便的。

以上就是Angular實(shí)踐之將Input與Lifecycle轉(zhuǎn)換成流示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Angular將Input Lifecycle轉(zhuǎn)流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • angular 內(nèi)存溢出的問(wèn)題解決

    angular 內(nèi)存溢出的問(wèn)題解決

    這篇文章主要介紹了angular 內(nèi)存溢出的問(wèn)題解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • 基于angularJS的表單驗(yàn)證指令介紹

    基于angularJS的表單驗(yàn)證指令介紹

    下面小編就為大家?guī)?lái)一篇基于angularJS的表單驗(yàn)證指令介紹。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10
  • angular4強(qiáng)制刷新視圖的方法

    angular4強(qiáng)制刷新視圖的方法

    今天小編就為大家分享一篇angular4強(qiáng)制刷新視圖的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • Angular.js中angular-ui-router的簡(jiǎn)單實(shí)踐

    Angular.js中angular-ui-router的簡(jiǎn)單實(shí)踐

    本篇文章主要介紹了Angular.js中angular-ui-router的簡(jiǎn)單實(shí)踐,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 詳解Angular6學(xué)習(xí)筆記之主從組件

    詳解Angular6學(xué)習(xí)筆記之主從組件

    這篇文章主要介紹了詳解Angular6學(xué)習(xí)筆記之主從組件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Angular之jwt令牌身份驗(yàn)證的實(shí)現(xiàn)

    Angular之jwt令牌身份驗(yàn)證的實(shí)現(xiàn)

    這篇文章主要介紹了Angular之jwt令牌身份驗(yàn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • AngularJS基礎(chǔ) ng-src 指令簡(jiǎn)單示例

    AngularJS基礎(chǔ) ng-src 指令簡(jiǎn)單示例

    本文主要介紹AngularJS ng-src 指令,這里對(duì)ng-src 指令的資料做了詳細(xì)整理,有需要的小伙伴可以參考下
    2016-08-08
  • Angular6實(shí)現(xiàn)拖拽功能指令drag實(shí)例詳解

    Angular6實(shí)現(xiàn)拖拽功能指令drag實(shí)例詳解

    這篇文章主要為大家介紹了Angular6實(shí)現(xiàn)拖拽功能指令drag實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 簡(jiǎn)單談?wù)凙ngular中的獨(dú)立組件的使用

    簡(jiǎn)單談?wù)凙ngular中的獨(dú)立組件的使用

    這篇文章主要介紹了簡(jiǎn)單談?wù)凙ngular中的獨(dú)立組件的使用的相關(guān)資料,通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),需要的朋友可以參考下
    2022-08-08
  • angularJS 指令封裝回到頂部示例詳解

    angularJS 指令封裝回到頂部示例詳解

    本篇文章主要介紹了angularJS 指令封裝回到頂部示例詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01

最新評(píng)論