angular9的学习(四)
指令 Directive
inputs
跟上一节一样,不过需要自己试试才知道
<div appEnabled [aaa]="123" [bbb]="456">12313131</div> @Directive({ selector: '[appEnabled]', inputs:['aaa'] }) export class EnabledDirective implements OnInit{ public aaa; @Input('bbb') b; constructor() { } ngOnInit(){ console.log(this.aaa); console.log(this.b); } }
outputs
父
<div appEnabled (bankName)="add($event)" (child)="add($event)>12313131</div>
add(e){
console.log(e)
}
子
@Directive({
selector: '[appEnabled]',
outputs:['bankName']
})
export class EnabledDirective implements OnInit{
public bankName=new EventEmitter();
@Output('child') c = new EventEmitter();
constructor() {
}
ngOnInit(){
this.bankName.emit('gggg');
this.c.emit('ccc')
}
}
providers 令牌
这个跟之前保持一致
exportAs 别名
我思考的时候一直在想这个有什么作用,后面才发现了,这个跟查找子组件的想法一样
@Directive({ selector: '[appEnabled]', exportAs: 'enabledDir' }) 父 <div appEnabled #dir='enabledDir' [red]="'sss'">12313131</div> //我竟然可以执行管道的方法 <button (click)="dir.add()">点击</button> export class EnabledComponent implements OnInit ,AfterViewInit{ constructor() { } @ViewChild('dir') dir; ngAfterViewInit(){ console.log(this.dir); } add(){ console.log(1) } }
queries
思考半天,还是不清楚这个属性的用意
host
绑定特定的键值对属性到DOM上
@Directive({
host:{
'one':'two'
}
})
HostListener 监听DOM事件
eventName |
要监听的DOM事件。 |
---|---|
args |
事件发生时传递给处理程序方法的一组参数。 |
<div appEnabled>点我</div>
@Directive({
selector: '[appEnabled]',
})
export class EnabledDirective{
@HostListener('click',['$event.target']) clickHandler(val){
console.log(val);
}
}
监控全局键盘事件
@HostListener('window:keydown', ['$event'])
keydownN(v:KeyboardEvent) {
console.log(v);
}
[属性绑定]
可以绑定一些自定义属性
<div [attr.name]="113">wqwwqwqwq</div>
[class绑定]
<h1 [class.aaa]="isSpecial">12112</h1>
isSpecial=true;
[style绑定]
<h1 [style.color]="'red'">122112</h1>
<h1 [style.font-size.px]="20">122112</h1>
<div [ngStyle]="{'font-size.px': 20, color: 'white', background: 'red'}">
Text in this div is 20px size, white color on red background.
</div>
伪事件
<input (keyup.enter)="enterHandler()">
<input (keydown.esc)="escHandler()">
<input (keyup.shift.f)="shiftFHandler()">
按 enter
按 esc
按 shift+f
main.ts
可以放入全局功能的js
动态组件
简单版
需求:添加一个动态组件,然后3s后删掉
模块
@NgModule({
declarations: [BlockComponent, UserComponent, EnabledComponent, RefsComponent, EnabledDirective, DyOneComponent, DyTwoComponent,AdHostDirective],
imports: [
BlockRoutingModule,
ComomModule
],
providers: [BlockService],
entryComponents: [DyOneComponent, DyTwoComponent] //添加动态的组件
})
指令
import {Directive, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[appAdHost]'
})
export class AdHostDirective {
constructor(public viewContainerRef:ViewContainerRef) { }
}
页面
<ng-template appAdHost></ng-template>
ts
export class BlockComponent implements OnInit, AfterViewInit {
@ViewChild(AdHostDirective) dlHost: AdHostDirective;
constructor(private cfr: ComponentFactoryResolver) {
}
ngAfterViewInit() {
this.dlHost.viewContainerRef.createComponent(
this.cfr.resolveComponentFactory(DyTwoComponent)
);
setTimeout(() => {
this.dlHost.viewContainerRef.clear();
}, 3000)
}
ngOnInit(): void {
}
}
稍微复杂点的版本
写一个定时器,3s切来切去
export class BlockComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild(AdHostDirective) dlHost: AdHostDirective; num: number = 0; interval: any; comArr = [DyOneComponent, DyTwoComponent]; constructor(private cfr: ComponentFactoryResolver) { } ngAfterViewInit() { this.addComponent() } ngOnDestroy() { clearInterval(this.interval) } addComponent() { this.interval = setInterval(() => { this.num = this.num > 1 ? 0 : this.num; this.dlHost.viewContainerRef.clear(); this.dlHost.viewContainerRef.createComponent( this.cfr.resolveComponentFactory(this.comArr[this.num]) ); this.num++; }, 3000) } ngOnInit(): void { } }
路由 Router
const appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },
{ path: 'hero/:id', component: HeroDetailComponent },
{
path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
{ path: '',
redirectTo: '/heroes',
pathMatch: 'full'
},
{ path: '**', component: PageNotFoundComponent }
];
路由器出口
<router-outlet></router-outlet>
多视口
<router-outlet></router-outlet>
<router-outlet name='left'></router-outlet>
<router-outlet name='right'></router-outlet>
{
path: '',
component: DyTwoComponent,
outlet:'left'
},
{
path: '',
component: RefsComponent,
outlet:'right'
}
弄了半天才踩出这个坑, 注意了name属性确定了, 该插件不能动态设置,只能写静态的,我尝试了很多种方法,跳转都报错,应该是静态的吧
路由导航
<a routerLinkActive="aaa" *ngFor="let item of arr" [routerLink]="item" [routerLinkActiveOptions]="{exact:true}">点我</a>
public arr=['','/pro/1','/one','/two'];
在链接的路由变成活动的时候将css添加类
<a routerLink="/user/bob" routerLinkActive="class1 class2">Bob</a> <a routerLink="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>
[routerLinkActiveOptions]="{exact:true}"
仅仅当url与链接完全匹配时,才添加routerLinkActive
里面的类
可以把
RouterLinkActive
实例分配给模板变量,检查isActive
状态简单的说就是鼠标点击的时候,拿到这个状态
<a routerLink="/user/bob" routerLinkActive="aaa" #rla="routerLinkActive"> Bob {{ rla.isActive ? '是' : '否'}} </a>
routerLink
<a routerLink="/user/bob">link to user component</a>
动态的
[routerLink]=['/team', teamId, 'user', userName, {details: true}]
/team/11/user/bob;details=true
如果第一段是前置
/
,./
,../
/ 根目录 ./ 当前路由的子级 ../ 上升一个级别
关于
# ?
<a [routerLink]="['/user/bob']" [queryParams]="{debug: true}" fragment="education"> link to user component </a> /user/bob#education?debug=true
ActivatedRoute 从节点中提取信息
{
path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
export class EnabledComponent implements OnInit {
this.route.data.subscribe(val=>{
console.log(val); //title: 'Heroes List'
})
constructor(private route: ActivatedRoute) {
}
ngOnInit(): void {
this.route.params.subscribe(val=>{
console.log(val); //动态的参数
});
this.route.url.subscribe(val=>{
console.log(val); // url
});
this.route.queryParamMap.subscribe(val=>{
console.log(val); // 所有的映射的参数
})
this.route.paramMap.subscribe(val=>{
console.log(val); //当前的,**这个用的多一些**
})
}
}
监控路由发生变化的事件
要写的专业点,修改原来的学习(二)的内容
export class AppComponent implements OnInit,OnDestroy{ routeEnd:Observable<NavigationEnd>; constructor(private router: Router) { this.routeEnd = this.router.events.pipe( filter(evt => evt instanceof NavigationEnd) ) as Observable<NavigationEnd>; } ngOnInit(){ this.routeEnd.subscribe(val=>{ console.log(val); }) } ngOnDestroy(){ this.routeEnd.unsubscribe() //不要忘记处理手动订阅 } }
路由复用策略
也可以叫缓存路由
RouteReuseStrategy
abstract class RouteReuseStrategy {
// 判断是否复用路由
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean
// 存储路由快照&组件当前实例对象
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void
// 判断是否允许还原路由对象及其子对象
abstract shouldAttach(route: ActivatedRouteSnapshot): boolean
// 获取实例对象,决定是否实例化还是使用缓存
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null
// 判断路由是否允许复用
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean
}
shouldReuseRoute
当要在路由之间导航的时候调用,调用这个方法并不代表一定会跳转到新的页面。
如果返回true, 那么不会进行跳转;如果返回false,才会跳转并且执行其余的那几个方法。
shouldDetach
离开页面的时候调用的方法, 会比落地页面的构造函数先执行
如果返回true,则会执行 store方法
store
shouldDetach
返回true的时候调用,可以在这里存储被detach下来的RouteHandle,
shoeldAttach
判断是否恢复之前的store路由
如果返回true的话,retrieve 方法会被调用
retrieve
返回之前存储的RouteHandle,如果返回null 的话则不起作用
创建一个服务
import {Injectable} from '@angular/core';
import {
ActivatedRouteSnapshot,
RouteReuseStrategy,
DetachedRouteHandle
} from '@angular/router'
@Injectable()
export class BlockService implements RouteReuseStrategy {
public handlers: { [key: string]: DetachedRouteHandle } = {};
//表示对路由允许复用
shouldDetach(route: ActivatedRouteSnapshot): boolean {
//默认对所有路由复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用,代码如下
//如果是懒加载路由需要在生命组件的位置进行配置
if (!route.data.keep) {
return false;
}
return true;
}
//当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const path = route.routeConfig?.path
if (path) {
this.handlers[path] = handle;
}
}
//若path在缓存中有的都认为允许还原路由
shouldAttach(route: ActivatedRouteSnapshot): boolean {
if(route.routeConfig?.path){
return !!this.handlers[route.routeConfig?.path]
}
return false
}
// 从缓存中获取快照,若无则返回null
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle| null {
if (!route.routeConfig) return null;
if (route.routeConfig.loadChildren) return null; //在loadChildren路径上通过修改自定义RouteReuseStrategy中的检索函数时从不检索分离的路由。
if(route.routeConfig?.path){
return this.handlers[route.routeConfig?.path];
}
return null
}
//进入路由触发,判断是否同一路由
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
return future.routeConfig === current.routeConfig;
}
}
在app.module.ts导入这个服务
providers: [{
provide: RouteReuseStrategy,
useClass: BlockService
}],
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬