码迷,mamicode.com
首页 > 其他好文 > 详细

angular11源码探索三[深入指令demo篇]

时间:2020-12-15 11:42:24      阅读:2      评论:0      收藏:0      [点我收藏+]

标签:use   mis   select   输入   app   属性   package   code   页面   

技术图片

\angular-master\packages\common\src\directives

模拟ngClass 方法

@Directive({
  selector: ‘[appNkClass]‘
})
export class NkClassDirective implements DoCheck {

  constructor(private renderer: Renderer2,
              private hostElement: ElementRef
  ) {
  }

  @Input(‘appNkClass‘) cssMap: Record<string, boolean>;

  ngDoCheck(): void {
    for (let [key, value] of Object.entries(this.cssMap)) {
      if (value === true) {
        this.renderer.addClass(this.hostElement.nativeElement, key);
      } else {
        this.renderer.removeClass(this.hostElement.nativeElement, key);
      }
    }
  }
}
<h1 [ngClass]="{active:flag}">xxxxxxxxxxx</h1>
<h1 [appNkClass]="{active:flag}">xxxxxxxxxxx</h1>

click属性里面编写方法

<button (click.long)="clickAdd()">Click2</button>

@Directive({
  selector: ‘[click.long]‘
})
export class clickLongDirective implements OnDestroy {
  /*设置一个方法,两s后执行*/
  private clickTimer: any;
  @Output(‘click.long‘)
  longClickEvent = new EventEmitter();

  @HostListener(‘mousedown‘)
  onMouse() {
    clearTimeout(this.clickTimer);
    this.clickTimer = window.setTimeout(() => {
      this.longClickEvent.emit();
    }, 2000);
  }

  ngOnDestroy() {
    clearTimeout(this.clickTimer);
  }

  constructor() {
  }
}

双向事件绑定

<input type="text"  [(nkModel)]="names">

 @Directive({
  selector: ‘[nkModel]‘
})
export class NkModelDirective {
  @Input(‘nkModel‘)
  dyName: string = ‘‘;
  @Output(‘nkModelChange‘)
  emitUpdates = new EventEmitter();

  @HostBinding(‘value‘)
  get value() {
    return this.dyName;
  }
          //change 事件是失去焦点触发
  @HostListener(‘input‘, [‘$event‘])
  update(event: Event) {
    this.dyName = (event.target as HTMLInputElement).value;
    this.emitUpdates.emit(this.dyName);
  }

  constructor() {
  }

}   

断网的时候竟用按钮

<button (click)="clickAdd()" appNkDisabled>CLIck</button>

@Directive({
  selector: ‘button[appNkDisabled]‘
})
export class NkDisabledDirective {
  /*需求没网的时候禁用按钮*/
  private _offline: boolean = false;

  @HostBinding(‘disabled‘)
  get isDisabled() {
    return  this._offline
  }

  /*断网*/
  @HostListener(‘window:offline‘)
  disableButton() {
    this._offline=true;
  }

  /*在线*/
  @HostListener(‘window:online‘)
  enableButton() {
    this._offline=false;
  }
  constructor() { }
}

写一个原生的textrea方法

@Directive({
  selector: ‘textarea‘
})
export class NkDisabledDirective {
  private readonly _textArea: HTMLTextAreaElement;
  @HostBinding(‘style‘)
  defaultStyle = {overflow: ‘hidden‘, height: ‘auto‘, resize: ‘none‘}

  // 输入数字的时候,高度随着行数的增加而增加
  @HostListener(‘input‘)
  autoExpand() {
    // 主要是随着滚动长度的增加height才会增加
    console.log(this._textArea.scrollHeight);
    //继承父级的高度
    this._textArea.style.height = ‘inherit‘
    const computed = window.getComputedStyle(this._textArea);
    const height = parseInt(computed.getPropertyValue(‘border-top-width‘), 10) + this._textArea.scrollHeight
      + parseInt(computed.getPropertyValue(‘padding-bottom‘), 10)
      + parseInt(computed.getPropertyValue(‘border-bottom-width‘), 10)
    this._textArea.style.height = height + ‘px‘;
  }

  constructor(private hostElement: ElementRef) {
    this._textArea = hostElement.nativeElement
  }
}

思考一个问题,window用的是全局的

为了使您的应用程序可以与服务器端渲染一起使用,我建议您不仅使用窗口直通令牌,而且还以SSR友好的方式创建此令牌,而无需完全引用window。Angular具有DOCUMENT用于访问的内置令牌document

看了写大佬写的

export const WINDOW=new InjectionToken<Window>(
‘return reference to window‘,
{providedIn:‘platform‘,factory:()=>window}
)

有个, 本地Web API的高质量轻量级包装器

可以看看源码学习下

然后把我们写好的WINDOW 注入到页面里面,代替我们写的window

conststructor(@Inject(WINDOW) private window)
替换之前的改成 this.window

有时间好好研究依赖注入,服务那块

*NgIf

<h1 *nkIf="flag">Hello World</h1>

@Directive({
  selector: ‘[nkIf]‘
})
export class NkDisabledDirective {
  @Input(‘nkIf‘)
  set IsHidden(shouldHide: boolean) {
    if (shouldHide) {
      this.viewContainer.clear()
    } else {
        // 插入新视图
      this.viewContainer.createEmbeddedView(this.template)
    }
  }

  constructor(
    private template: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) {
  }

}

ngTemplateOutlet

将一个或者多个组件插入视图中

@Directive({
  selector: ‘[nkComponent]‘
})
export class NkDisabledDirective {
 /*Type 实例类*/
  @Input(‘nkComponent‘)
  set componentToRender(component: Type<any>) {
    // 拿到当前组件dom
    // console.log(this.viewContainer.element);
    // 清空当前的组件
    this.viewContainer.clear()
    // 通过注入器取出 用于获取给定组件类型的工厂函数
    const resolver = this.viewContainer.injector.get(ComponentFactoryResolver);
    // 通过实例化组件
    this.viewContainer.createComponent(resolver.resolveComponentFactory(component))
  }

  constructor(
    private viewContainer: ViewContainerRef
  ) {
  }

}
<ng-container *ngTemplateOutlet="bool"></ng-container>
// 模拟
<div [nkComponent]="bool"></div>

// 外部引入的组件
  bool = CountDownComponent;

ngFor探索

@Directive({
  selector: ‘[nkForMap]‘
})
export class NkDisabledDirective implements DoCheck {
  @Input(‘nkForMapIn‘) map;
  @Input(‘nkForMapFilter‘) filter;
  constructor(private viewContainer: ViewContainerRef,
              private template: TemplateRef<any>) {
  }

  ngDoCheck(): void {
    // 可以拿到值
    console.log(this.filter);
    // 进行for-in操作
    Object.keys(this.map).forEach(key => {
      this.viewContainer.createEmbeddedView(this.template,{$implicit:{key:key,value:this.map[key]}})
    })
  }
}
<ul>
  <li *nkForMap="let entry in user;filter:‘s‘">{{entry.key}}{{entry.value}}</li>
</ul>

  user = {
    name: ‘xxx‘,
    email: ‘bbbb‘,
    age: 123
  }

获取剪贴栏的内容

<input type="text" (keydown.paste)="clickDown($event)"  [(ngModel)]="str">

  str: string;
 clickDown(content) {
    //获取剪贴栏的内容
    this.str=content
  }

@Directive({
  selector: ‘[keydown.paste]‘
})
export class NkModelDirective {
  @Output(‘keydown.paste‘)
  pasteEvent = new EventEmitter<string>();

  @HostListener(‘keydown‘, [‘$event‘])
  async detectPaste(event) {
    // 按下ctrl
    // console.log($event.ctrlKey);
    //     按下p
    // console.log($event.code== ‘KeyP‘);
    // 按下ctrl+i
    // 解析系统剪贴板的文本内容返回一个Promise 。
    // navigator.clipboard.readText()
    if (event.ctrlKey && event.code === ‘KeyI‘) {
      const content = await navigator.clipboard.readText();
      this.pasteEvent.emit(content);
    }
  }
  constructor() {
  }
}

ngComponentOutlet

<ng-container *ngComponentOutlet="two"></ng-container>

export class OneComponent implements OnInit, AfterViewInit {
  // 组件
  public two=TwoComponent
}
<div *ngFor="let comp of comps">
  <ng-container *ngComponentOutlet="comp"></ng-container>
</div>
把三个组件放在 comps 数组中
  comps: any[] = [
    OneComponent,
    TwoComponent,
    ThreeComponent
  ];

angular11源码探索三[深入指令demo篇]

标签:use   mis   select   输入   app   属性   package   code   页面   

原文地址:https://www.cnblogs.com/fangdongdemao/p/14106432.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!