cdk Stepper 让我们能够更好的处理类似于工作流的情况(任务分为多个步骤,上一步操作完成之后进入下一步的操作,比如咱们休假申请单要经过多个领导的审批的情况)。
还是和之前cdk 里面其他功能模块一样,要使用Stepper 需provider CdkStepperModule的。
import {CdkStepperModule} from '@angular/cdk/stepper';
cdk Stepper看起来复杂其实里面的东西不是很多。整个Stepper都是围绕一个组件CdkStep(cdk-step)和6个指令(CdkStepper、CdkStepLabel、CdkStepperNext、CdkStepperPrevious、CdkStepHeader)来展开的。咱们上面不是说了么,cdk Stepper一般用来处理多个步骤任务。这里每个任务的内容用CdkStep组件来表示,所以有多少个步骤就会 有多少个CdkStep组件。CdkStepper指令呢则是用来管理这些组件比如跳到下一步,上一步,完成等等(所以cdk Stepper使用的时候我们需要另外定义一个组件继承自CdkStepper指令,我们可以把他当做是工作流组件)。CdkStepperNext、CdkStepperPrevious两个指令正好对应上一步下一步,一般会添加在button上面包含在CdkStep组件里面,因为每个步骤都可能有上一步,下一步这样的。CdkStepLabel指令则是对每一个步骤的描述你也可以认为是每个步骤的标题。CdkStepHeader指令一般则是用来表示当前进行到哪一步了。一般也是会自定义一个组件继承CdkStepHeader实现。
一 CdkStep
CdkStep其实是一个组件来着。表示每个步骤的内容。所以任务有多少步就会有多少个CdkStep。比如如下代码有两个步骤所以有两个CdkStep(cdk-step):
cdk stepper
第一步
第二步
每个CdkStep组件里面的内容对应每个步骤的内容。
Selector: cdk-step
Exported as: cdkStep
1.1 CdkStep组件属性
属性 | 内容 | 解释 |
---|---|---|
ariaLabel: string | @Input('aria-label') | 添加aria-label属性 |
ariaLabelledby: string | @Input('aria-labelledby') | 添加aria-labelledby属性 |
completed: boolean | @Input() | 当前步骤是否标记为完成状态 |
editable: boolean | @Input() | 当前步骤标记为完成之后,是否还可以回到该步骤 |
errorMessage: string | @Input() | 错误信息 |
hasError: boolean | @Input() | 是否有错误 |
label: string | @Input() | 当前步骤对应的label,和cdkStepLabel指令的作用是一样的(可以简单的把他认为是步骤的标题) |
optional: boolean | @Input() | 当前步骤是否是可选的 |
state: StepState | @Input() | 当前步骤的状态 |
stepControl: AbstractControl | @Input() | 用于验证当前步骤的合法性 |
content: TemplateRef |
当前步骤 试图元素内容 | |
interacted: false | 用户是否看到当前步骤内容 | |
stepLabel: CdkStepLabel | 当前步骤label内容 |
1.2 CdkStep组件方法
export declare class CdkStep implements OnChanges {
...
/** 选中当前步骤(select哪个步骤则选中那个步骤) */
select(): void;
/** 设置当前步骤到无效状态 */
reset(): void;
...
}
CdkStep组件里面大部分的方法都需要配合我们下面要讲的CdkStepper指令来使用
二 CdkStepper
CdkStepper是一个指令,用来管理所有的步骤,即CdkStepper是用来管理CdkStep组件的。一般的做法是自定义一个组件继承CdkStepper指令。并且CdkStep组件是这个组件的子组件。比如如下的代码我们定义一个StepperComponent组件继承CdkStepper指令:
import {
AfterContentInit,
ChangeDetectionStrategy,
Component,
ContentChildren,
EventEmitter,
Output,
QueryList,
ViewEncapsulation
} from '@angular/core';
import {AnimationEvent} from '@angular/animations';
import {CdkStep, CdkStepper, StepContentPositionState} from '@angular/cdk/stepper';
import {Subject} from 'rxjs';
import {distinctUntilChanged, takeUntil} from 'rxjs/operators';
import {yxStepperAnimations} from './stepper-animations';
@Component({
selector: 'yx-stepper',
templateUrl: './stepper.component.html',
styleUrls: ['./stepper.component.less'],
providers: [{provide: CdkStepper, useExisting: StepperComponent}],
animations: [yxStepperAnimations.horizontalStepTransition],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StepperComponent extends CdkStepper implements AfterContentInit {
/** Steps that the stepper holds. */
@ContentChildren(CdkStep) _steps: QueryList;
/** Event emitted when the current step is done transitioning in. */
@Output() readonly animationDone: EventEmitter = new EventEmitter();
_animationDone = new Subject();
ngAfterContentInit() {
// Mark the component for change detection whenever the content children query changes
this._steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => this._stateChanged());
this._animationDone.pipe(
// This needs a `distinctUntilChanged` in order to avoid emitting the same event twice due
// to a bug in animations where the `.done` callback gets invoked twice on some browsers.
// See https://github.com/angular/angular/issues/24084
distinctUntilChanged((x, y) => x.fromState === y.fromState && x.toState === y.toState),
takeUntil(this._destroyed)
).subscribe(event => {
if ((event.toState as StepContentPositionState) === 'current') {
this.animationDone.emit();
}
});
}
}
Selector: [cdkStepper]
Exported as: cdkStepper
2.1 CdkStepper属性
属性 | 类型 | 解释 |
---|---|---|
linear: boolean | @Input() | 任务流是否是线性的,前一个任务完成才能进行下一个任务 |
selected: CdkStep | @Input() | 当前选中的任务 |
selectedIndex: number | @Input() | 当前选中任务的index |
selectionChange: EventEmitter |
@Output() | 选中任务改变时候的回调函数 |
2.2 CdkStepper方法
export declare class CdkStepper implements AfterViewInit, OnDestroy {
...
/** 切换到下一个任务 */
next(): void;
/** 切换到上一个任务 */
previous(): void;
/** 重置所有的任务 */
reset(): void;
...
}
关于CdkStepper的使用更加详细的任务可以参考下下文中代码链接。
三 CdkStepLabel
指令,每个步骤需要显示的label内容,比如如下代码
第一步
Selector: [cdkStepLabel]
四 CdkStepperNext
添加在button上的指令,跳到下一个任务。
Selector: button[cdkStepperNext]
五 CdkStepperPrevious
添加在button上的指令,跳到上一个任务。
Selector: button[cdkStepperPrevious]
六 CdkStepHeader
指令,每个任务的头部信息,任务指示器。
关于cdk Stepper部分的内容好像也没啥讲的,关键点就在咱们继承CdkStepper的组件怎么来写了,怎么来管理这些workflow里面的任务。所以最最重要的在代码实现部分。为了能让大家更加直观的知道cdk Stepper怎么使用,这里我就直接写了一个非常简单的例子。有兴趣的大家可以看看例子里面是怎么做到的 https://github.com/tuacy/angular-cdk-study cdk stepper部分内容在workflow-stepper文件下面。实现效果图如下: