小括号可以说是这个类在实例化是便加载的成员变量[注意,不是new一个对象需要传参!!]
Ts构造器中所谓的参数严格意义上应该称为依赖,在小括号中注入,在大括号中进行逻辑处理
如果一个组件的模板中以html标记的形式调用了另一个组件模板,那么被调用的组件(整个组件)就是子组件
而调用者组件即为父组件
在父组件标记中包含着子组件,这时浏览器渲染出的结果为父节点与子节点
angular的每个组件在一定的生命周期都会提供一些业务接口,只要实现这些接口就可以在到达一定的时期时执行所重写的钩子函数
具体的钩子函数以及执行的时间顺序如下:
constructor -> ngOnChanges -> ngOnInit -> ngDoCheck -> ngAfterContentInit ->
ngAfterContentChecked -> ngAfterViewInit -> ngAfterViewChecked -> ngOnDestroy
各钩子函数的目的:
使用场景:想要子Dom节点显示在指定的位置
占位符,又叫做组件插槽,标签类的自定义属性会被忽略,因为不会产生Dom元素,当组件模板中含多个ng-content时,可以使用select来匹配指定的元素进行显示
这里的匹配只匹配第一层即插槽之中的那一层,而包含一个div或者其他标签中是无法显示内容的
使用场景:需要显示一定量的内容但是不想要产生大量的Dom元素,或者当需要同时使用 ngIf 和 ngFor指令时(在同一个元素中使用这两个指令会报错)
有条件的内容投影(可用ngIf控制),可以使用 templateRefExp 来匹配模板ID(模板变量),使用context来匹配组件类中所提供的数据,可以使用ng-template投影context
中的数据,默认为implicit,ng-template可以在外部然后用ContentChild获取到实例再使用templateRefExp匹配
<ng-container *ngTemplateOutlet="templateRefExp; context: contextExp">ng-container>
例子:
<ng-container *ngTemplateOutlet="testID;context:myContext">ng-container>
<ng-template #testID let-displayValue="默认如果不指定键名为implicit,但显示其他值需要指定键名">{{ displayValue }}ng-template>
// .ts文件
contextExp = {$implicit:'value1',otherValue:'value2'}
等待其他元素召唤的内容显示,会产生Dom元素,ng-template会被angualr视作一个TemplatRef实例对象,如果想要在组件类中创建ng-template,可以先获取到装ng-template的
容器并转型为ViewTemplateRef,然后再使用createEmbeddedView()方法创建出一个个TemplateRef实例,这些实例会在模板上被渲染成ng-template显示出来,与createEmbeddedView
方法相似的还有一个createComponent方法,这个方法可以动态的创建组件ComponentRef,ng-template 不可以自主控制地显示里面的内容,必须让它地引用者来控制显示,ng-template
可以和ng-content联合使用
例子:
<ng-container #father>ng-container>
<ng-template #son let-impicit>{{ impicit }}ng-template>
embedContext = {$implicit:'embedimplicit',localvalue:'embedotherValue'};
@ViewChild('test')
tmp!: TemplateRef
@ViewChild('father',{read:ViewContainerRef})
tmpFather!: ViewContainerRef
ngAfterViewInit(): void {
this.tmpFather.createEmbeddedView(this.tmp,this.embedContext)
}
注: 如果想要有条件的显示某块内容或多次显示某块内容,推荐使用ng-template而不推荐ng-content
这两个装饰器主要用来进行父子组件之间的通信
其中
@Input 修饰子类组件中的property,表示允许父类组件的数据流入
===> 在子组件选择标记中绑定数据
@Output 也是在子类组件中修饰,表示可以向父类发送数据,被@Output修饰过的为Observable类
===> 在父组件模板的子组件选择标记中绑定事件(数据)在父类组件中定义接受事件
两个都是在子组件类中修饰,一个从外接收,另一个向外发送
两个都是在父组件模板中的子组件标记中绑定数据或事件的,@Output 是在父组件类中定义数据接收事件
官方一直推荐使用[]进行数据绑定,使用 [] 与{{}} 的唯一区别就是后者会将变量解析后再转化为字符串
.parent{
.first{}
.second{}
}
这时相加一个.third{}可以在相应的模板中加上[parent.third]=“true”,这个true可以通过方法,也可以通过变量
使用方法:
当在一个组件模板中调用另一个组件模板时如
@ContentChildren [@ContentChild同理]
// 这里要明白Content Dom 和子组件调用的区别
// parent.compnent.html
// app.component.html
// 此时的Dom树为
// app.component.html
// 此时的Dom树为
当一个child Element被加时,受@ContentChildren()
注解所修饰的QuerryList也会更新,这里强调的是Content 以及 Element
与子组件的调用完全不同,必须是某个模板标签包裹着另外的模板标签(子Element)
才会生效
ViewChild用来获取视图模板中与选择器匹配成功的的Dom,常和模板变量以及ElementRef联用,用来获取
模板中的原生dom
参数: selector|read|static
selector: 选择器,一般匹配内容为模板变量或者类名
read: 每个元素都有一个ElementRef和ViewContainerRef,ViewChild默认返回ElementRef
如果需要从获取的Dom中获取别的东西,需要通过read特殊指定
static: 是否静态,当设置为true时在定义的change 运行之前加载查询结果,设置为false时
在change运行之后加载查寻结果,默认为false
@Option: angular会通过此注解将注入的服务认为是可执行服务,以至于当无法解析注入的服务时仅仅会返回null而不会报出错误
@SkipSelf: 当父子组件都使用相同的provider,但是不想使用子组件的provider而想使用父级注入器所提供的
@Self: 只在它自己组件类中的providers中加载依赖
当一个类要作为一个dependency提供出去时,需要使用@Injector装饰器装饰,我们只需要将依赖注册到消费者的构造器中,angular会自动创建依赖的实例对象
但是前提是必须要声明依赖提供者,需要在指令或组件的@Component装饰器通过provider声明
用来获取依赖类的实例
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css'],
providers:[{provide: TestInjectorService, useClass:TestInjectorService}]
})
provide: 提供让angular DI框架解析的token来获取依赖实例,默认是类名
useClass: 在依赖注入时告诉DI 框架将useClass指定的类实例化,provide可以是基类名,然后使用指定扩展类使用扩展功能,如果依赖提供者本身也有自己的依赖
需要将提供者的依赖也声明在消费者的provider中
useExisting: 用一个新的token来代替已经存在的token ,其中provide所指出的token实际上使用的是useExisting指出的token,即第一个token是第二个token的别名
useFactory: 使用工厂方法返回实例对象
useValue: 使用静态值
forwardRef方法: 解决以下的问题
interface ControlValueAccessor {
// 向Dom Elelment写入一个新的值
writeValue(obj: any): void
// 当组件的control的值发生改变时注册被调用的回调函数
registerOnChange(fn: any): void
// 当组件的焦点离开(组件被触发过了)时注册被调用的回调函数
registerOnTouched(fn: any): void
setDisabledState(isDisabled: boolean)?: void
}
在项目中,parent 如何通过抽象类获取到子组件节点的?
@ContentChild/@ContentChildren的selector可以匹配到以下标识
而父组件也使用了ng-content占位符,所以说被包住的模板标记就是该组件的子组件
Any class with the @Component or @Directive decorator
A template reference variable as a string (e.g query
Any provider defined in the child component tree of the current component (e.g. @ContentChild(SomeService) someService: SomeService)
Any provider defined through a string token (e.g. @ContentChild(‘someToken’) someTokenVal: any)
A TemplateRef (e.g. query with @ContentChild(TemplateRef) template;)
其实在项目中使用这两种方式都可以获取到子节点
provide:'Child',useExisting:forwardRef(()=>ChildComponent)
provide:Child,useExisting:forwardRef(()=>ChildComponent)
项目中子组件如何获取到父节点:
安装配置@ngrx/shematics链接: https://ngrx.io/guide/schematics
注: 需要在angular.json 中配置,添加一项
"cli": {
"defaultCollection": "@ngrx/schematics",
}
–module: 指定模块名,在该模块中的import选项中添加StoreModule
–statePath: State文件放置路径
–stateInterface: State 数据结构
–root: store也是以模块为单位的,当要生成的store属于根模块,要加上–root选项,否则便不需要加
//指定要选择哪一个特征
export const selectFeature = (state:StateData) => state.countState;
/*
*特征选择其另外一种写法
export const selectFeature = createFeatureSelector(newReducerFeatureKey)
*/
//选择指定特征的状态
export const selectFeatureCount = createSelector(selectFeature,(state) => state.count)
Injector[abstract]
//Injector use
class Square {
name = 'square';
}
// 配置Injector,创建注入器
const injector = Injector.create({providers: [{provide: Square, deps: []}]});
// 获取provider的实例
const shape: Square = injector.get(Square);
// Using `coerceBooleanProperty` allows for the disabled value of a button to be set as
// ` ` instead of ` `.
// It also allows for a string to be passed like ` `.
@Input()
get disabled() { return this._disabled; }
set disabled(value: BooleanInput) {
this._disabled = coerceBooleanProperty(value);
}
private _disabled = false;
coerceBooleanProperty
//只要指定了属性(无论是否赋值),都将转化为布尔值true
/**
* ... 三点语法可以抽取数组中的数据,相当于将[]剥掉
*/
let arr = [1,2,3,4]
console.log(arr)
let brr = [true,"Alan",...arr]
console.log(brr)
//结果
PS C:\ node .\test.js
[ 1, 2, 3, 4 ]
[ true, 'Alan', 1, 2, 3, 4 ]