zoukankan      html  css  js  c++  java
  • 【转】angular 自定义 component decorator

    https://netbasal.com/inspiration-for-custom-decorators-in-angular-95aeb87f072c

    以下代码使用了 class decorator, method decorator, property decorator

    import { environment } from 'src/environments/environment';
    import { Component, OnChanges, Input } from '@angular/core';
    import { AppModule } from 'src/app/app.module';
    import { Observable } from 'rxjs';
    
    export function NgLog(): ClassDecorator {
      return (constructor: any) => {
        console.log('cons:', constructor);
        if (!environment.production) {
          // You can add/remove events for your needs
          const LIFECYCLE_HOOKS = [
            'ngOnInit',
            'ngOnChanges',
            'ngOnDestroy'
          ];
          const component = constructor.name;
    
          LIFECYCLE_HOOKS.forEach(hook => {
            console.log('123:',hook);
            const original = constructor.prototype[hook];
    
            constructor.prototype[hook] = function (...args) {
              console.log(`%c ${component} - ${hook}`, `color: #4CAF50; font-weight: bold`, ...args, constructor.prototype);
              original && original.apply(this, args);
            }
          });
        }
    
      }
    } 
    
    export function PageTrack(pageName: string): ClassDecorator {
    
      return function (constructor: any) {
        // const analyticsService = AppModule.injector.get(AnalyticsService);
    
        const ngOnInit = constructor.prototype.ngOnInit;
    
        constructor.prototype.ngOnInit = function (...args) {
          // analyticsService.visit(pageName);
          console.log(`%c visit: ${pageName}`, `color: #4CAF50; font-weight: bold`);
          ngOnInit && ngOnInit.apply(this, args);
        }
    
        const ngOnDestroy = constructor.prototype.ngOnDestroy;
    
        constructor.prototype.ngOnDestroy = function (...args) {
          // analyticsService.leave(pageName);
          console.log(`%c leave: ${pageName}`, `color: green; font-weight: bold`);
          ngOnDestroy && ngOnDestroy.apply(this, args);
        }
    
      }
    }
    
    
    export function log$(target: any, propertyKey: string) {
      let propertyValue;
    
      function getter() {
        return propertyValue;
      }
    
      function setter(value: any) {
        if (value instanceof Observable) {
          propertyValue = value.forEach(res => {
            const isArrayOfObjects = Array.isArray(res) && typeof res[0] === 'object';
            const logType = isArrayOfObjects ? 'table' : 'log';
            console.groupCollapsed(propertyKey);
            console[logType](res);
            console.groupEnd();
          });
        } else {
          console.error('none observable', value);
          propertyValue = value;
        }
      }
    
      Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
      });
    }
    
    
    export function throttle(milliseconds: number = 500): MethodDecorator {
      return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const original = descriptor.value;
        descriptor.value = () => {
          console.error('throttle...........');
        }
        return descriptor;
      };
    }
    
    
    @Component({
      selector: 'fly-aa',
      template: `
        <div >zzzzz {{zz}}</div>
      `
    })
    @NgLog()
    @PageTrack("fly")
    export class FlyComponent implements OnChanges {
      @Input() @log$ zz: string;
       name = 'Angular';
       
      mm() {
        console.log('m');
      }
    
      @throttle()
      ngOnChanges(ss) {
        console.log('cha:', ss);
      }
      ngOnDestory(ss) {
        console.log('destroy:', ss);
      }
    }
    

      

    -------------------------------------------------------------

    This post assumes that you at least have some working knowledge of Angular and Decorators.

    If you have no prior knowledge on the subject, you can read the following articles:

    NgLog Class Decorator

    This decorator will be helpful for debugging purposes. We will log the ngOnInitngOnDestroy and ngOnChanges lifecycle hooks.

    import { environment } from "../environments/environment";
    export function NgLog() : ClassDecorator {
      return function ( constructor : any ) {
        if( !environment.production ) {
          // You can add/remove events for your needs
          const LIFECYCLE_HOOKS = [
            'ngOnInit',
            'ngOnChanges',
            'ngOnDestroy'
          ];
          const component = constructor.name;
    
          LIFECYCLE_HOOKS.forEach(hook => {
            const original = constructor.prototype[hook];
    
            constructor.prototype[hook] = function ( ...args ) {
              console.log(`%c ${component} - ${hook}`, `color: #4CAF50; font-weight: bold`, ...args);
              original && original.apply(this, args);
            }
          });
        }
    
      }
    }
    

      

    We just log the hook and calling the original method. Let’s use the decorator.

    @Component({
      selector: 'posts-page',
      template: `
        <posts [posts]="posts$ | async"></posts>
      `
    })
    @NgLog()
    export class PostsPageComponent {
      constructor( private store : Store<any> ) {
        this.posts$ = store.select('posts');
      }
    }
    
        
    @Component({
      selector: 'posts',
      template: `
        <p *ngFor="let post of posts">{{post.title}}</p>
      `
    })
    @NgLog()
    export class PostsComponent implements OnInit {
      @Input() posts = [];
    }
    

      

    Throttle Method Decorator

    This decorator will be helpful when working for example with scroll events.

    import t from 'lodash.throttle';
    
    export function throttle( milliseconds : number = 500 ) : MethodDecorator {
      return function ( target : any, propertyKey : string, descriptor : PropertyDescriptor ) {
        const original = descriptor.value;
        descriptor.value = t(original, milliseconds);
        return descriptor;
      };
    }
    

      

    We are using the throttle helper from lodash and replacing the original method with our “throttle” version. Let’s use the decorator.

    @Component({
      selector: 'app-posts-page',
      template: `
         <posts [posts]="posts$ | async"></posts>
      `
    })
    export class PostsPageComponent {
      constructor( private store : Store<any> ) {
        this.posts$ = store.select('posts');
      }
    
      @HostListener('document:scroll')
      @throttle()
      scroll() {
        console.log('scroll');
      }
    
    }
    

      

    Track Page Class Decorator

    This decorator will be helpful when you need to report page visits to your analytics provider.

    import { AnalyticsService, AppModule } from "./app.module";
    export function PageTrack( pageName : string ): ClassDecorator {
    
      return function ( constructor : any ) {
        const analyticsService = AppModule.injector.get(AnalyticsService);
    
        const ngOnInit = constructor.prototype.ngOnInit;
    
        constructor.prototype.ngOnInit = function ( ...args ) {
          analyticsService.visit(pageName);
          ngOnInit && ngOnInit.apply(this, args);
        }
    
        const ngOnDestroy = constructor.prototype.ngOnDestroy;
    
        constructor.prototype.ngOnDestroy = function ( ...args ) {
          analyticsService.leave(pageName);
          ngOnDestroy && ngOnDestroy.apply(this, args);
        }
    
      }
    }
    

      

    Based on the hook we can call the appropriate method from our Analytics service then invoke the original method.

    @Component({
      ...
    })
    @PageTrack('blog')
    export class PostsPageComponent {
    
      constructor( private store : Store<any> ) {
        this.posts$ = store.select('posts').pluck('data');
      }
    
    }
    

      

    Log Observable Property Decorator

    This decorator will be helpful for debugging purposes. You can also achieve the same thing with a custom operator.

    export function log$( target : any, propertyKey : string ) {
      let propertyValue;
    
      function getter() {
        return propertyValue;
      }
    
      function setter( value : any ) {
        if( value instanceof Observable ) {
          propertyValue = value.do(res => {
            const isArrayOfObjects = Array.isArray(res) && typeof res[0] === 'object';
            const logType = isArrayOfObjects ? 'table' : 'log';
            console.groupCollapsed(propertyKey);
            console[logType](res)
            console.groupEnd();
          });
        } else {
          propertyValue = value;
        }
      }
    
      Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
      });
    }
    

      

    We can get the observable and add the do operator to log the value. Based on the value we can choose between console.table or console.log .

    Let’s use the decorator.

    @Component({
      selector: 'posts-page',
      template: `
          <posts [posts]="posts$ | async"></posts>
      `
    })
    export class PostsPageComponent implements OnInit {
    
      @log$ posts$ : Observable<Post[]>;
        
      constructor( private store : Store<any> ) {
        this.posts$ = store.select('posts');
      }
    
    }
    

      

    Conclusion:

    You can leverage decorators in your apps and create powerful things with them. Decorators are not only for frameworks or libraries, so be creative and start using them.

    Follow me on Medium or Twitter to read more about Angular, JS and Vue.

  • 相关阅读:
    处理视频流时可能出现的重复帧问题及解决办法
    shell脚本中cd命令无效
    C++教程之初识编程
    若干排序算法的Python实现方法及原理
    C/C++反三角函数使用注意
    ubuntu下安装pip install mysqlclient 报错 command "python setup.py egg_info" failed with error.....解决方案
    使用scrapy框架的monkey出现monkeypatchwarning: monkey-patching ssl after ssl...的解决办法
    机器学习之利用KNN近邻算法预测数据
    python数据分析的工具环境
    python代码实现经典排序算法
  • 原文地址:https://www.cnblogs.com/oxspirt/p/14362644.html
Copyright © 2011-2022 走看看