组件指令间经常需要沟通

我们知道的方式有

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);  });

}

Angular 学习笔记 (组件沟通的思考)的更多相关文章

  1. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  2. angular学习笔记(三十一)-$location(1)

    本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...

  3. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  4. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  5. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  6. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  7. angular学习笔记(三十)-指令(5)-link

    这篇主要介绍angular指令中的link属性: link:function(scope,iEle,iAttrs,ctrl,linker){ .... } link属性值为一个函数,这个函数有五个参数 ...

  8. angular学习笔记(三十)-指令(2)-restrice,replace,template

    本篇主要讲解指令中的 restrict属性, replace属性, template属性 这三个属性 一. restrict: 字符串.定义指令在视图中的使用方式,一共有四种使用方式: 1. 元素: ...

  9. angular学习笔记(三十)-指令(1)-概述

    之前在 angular学习笔记(十九)-指令修改dom 里面已经简单的提到了angular中的指令,现在来详细的介绍 '指令' 一.指令的创建: dirAppModule.directive('dir ...

随机推荐

  1. 线程同步-Barrier类

    Barrier类:用于组织多个线程及时在某一个时刻碰面.并提供了一个回调函数,每次线程调用了SignalAndWait方法后该回调函数会被执行. 代码Demo: using System;using ...

  2. mysql-proxy 简介

    # 背景 今天同事分享的主题就是mysql-proxy,于是下来自己了解下,不求精通,只求知道这个玩意 # 简介 mysql-proxy是mysql官方提供的mysql中间件服务,上游可接入若干个my ...

  3. WebDriver API--元素定位

    WebDriver属于Selenium体系中设计出来操作浏览器的一套API, 站在WebDriver的角度, 因为它针对多种编程语言都实现了一遍这套API,所以它可以支持多种编程语言: 站在编程语言的 ...

  4. CH#46 磁力块 分块

    正解:分块+bfs 解题报告: 先放个传送门,然后瞎扯淡下QAQ 突然感觉不停课大概是正确的选择QAQ 大概实在是没有天赋?明明都知道正解是分块甚至还听了下解法感觉理解了,再看一次依然没想到解法,,, ...

  5. Centos下搭建邮件服务器

    一.协议 SMTP:用于发送邮件 POP3:用于接收邮件,接收后会将服务器上邮件删除 IMAP:用于接收邮件,接收后不会删除服务器邮件 二.几个重要的角色 MUA:可以理解为收取邮件的工具,比如thu ...

  6. .net core 获取不到session 和cookies的值

    在启动类的configure services()方法中,设置选项.checkconsent必需=context=false;如下: services.Configure<CookiePolic ...

  7. PHP自定义curl请求

    function http_post($url,$param,$post_file=false,$headers=[]){ $oCurl = curl_init(); if(stripos($url, ...

  8. 在 Django/Flask 开发服务器上使用 HTTPS

    使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署.问题是这些内建服务器通常都不支持 HTTPS,我们想在开发 ...

  9. eclipse 中配置php的 XDebug调试

    1. 打开 eclipse for php IDE,window->preference->PHP->Debug 2. 配置phpserver 3. 我的已经增加好了,默认的应该有l ...

  10. Hibernate映射数据库中longtext类型属性时报错No Dialect mapping for JDBC type: -1的解决方案

    出现错误的原因是:hibernate中对于数据库的longtext数据类型不支持. 解决方案: 1.写个类集成方言,然后自己实现对longtext的支持 import java.sql.Types; ...