open<T>(
componentOrTemplateRef: ComponentType<T> | TemplateRef<T>,
config?: MatDialogConfig
): MatDialogRef<T> {
// 防止重复打开
const inProgressDialog = this.openDialogs.find(dialog => dialog._isAnimating());
if (inProgressDialog) {
return inProgressDialog;
}
// 组合配置
config = _applyConfigDefaults(config);
// 防止id冲突
if (config.id && this.getDialogById(config.id)) {
throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`);
}
// 第一步:创建弹出层
const overlayRef = this._createOverlay(config);
// 第二步:在弹出层上添加弹窗容器
const dialogContainer = this._attachDialogContainer(overlayRef, config);
// 第三步:把传入的组件添加到创建的弹出层中创建的弹窗容器中
const dialogRef = this._attachDialogContent(componentOrTemplateRef, dialogContainer, overlayRef, config);
// 首次弹窗要添加键盘监听
if (!this.openDialogs.length) {
document.addEventListener('keydown', this._boundKeydown);
}
// 添加进队列
this.openDialogs.push(dialogRef);
// 默认添加一个关闭的订阅 关闭时要移除此弹窗
// 当是最后一个弹窗时触发全部关闭的订阅并移除键盘监听
dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef));
// 触发打开的订阅
this.afterOpen.next(dialogRef);
return dialogRef;
}
create(config: OverlayConfig = defaultConfig): OverlayRef {
const pane = this._createPaneElement(); // 弹出层DOM 将被添加到宿主DOM中
const portalHost = this._createPortalHost(pane); // 宿主DOM 将被添加到<body>末端
return new OverlayRef(portalHost, pane, config, this._ngZone); // 弹出层的引用
}
private _createPaneElement(): HTMLElement {
let pane = document.createElement('div');
pane.id = `cdk-overlay-${nextUniqueId++}`;
pane.classList.add('cdk-overlay-pane');
this._overlayContainer.getContainerElement().appendChild(pane); // 将创建好的带id的弹出层添加到宿主
return pane;
}
private _createPortalHost(pane: HTMLElement): DomPortalHost {
// 创建宿主
return new DomPortalHost(pane, this._componentFactoryResolver, this._appRef, this._injector);
}
getContainerElement(): HTMLElement {
if (!this._containerElement) { this._createContainer(); }
return this._containerElement;
}
protected _createContainer(): void {
let container = document.createElement('div');
container.classList.add('cdk-overlay-container');
document.body.appendChild(container); // 在body下创建顶层的宿主 姑且称之为弹出层容器(OverlayContainer)
this._containerElement = container;
}
constructor(
private injector: Injector
// private 服务: 服务类 // 这样是无效的
) {
this.服务 = injector.get('服务类名');
}
<ng-template cdkPortalHost></ng-template>
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
// 创建工厂
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component);
let componentRef: ComponentRef<T>;
if (portal.viewContainerRef) {
componentRef = portal.viewContainerRef.createComponent(
componentFactory,
portal.viewContainerRef.length,
portal.injector || portal.viewContainerRef.parentInjector);
this.setDisposeFn(() => componentRef.destroy());
// 暂不知道为何有指定宿主后面还要把它添加到宿主元素DOM中
} else {
componentRef = componentFactory.create(portal.injector || this._defaultInjector);
this._appRef.attachView(componentRef.hostView);
this.setDisposeFn(() => {
this._appRef.detachView(componentRef.hostView);
componentRef.destroy();
});
// 到这一步创建出了经angular处理的DOM
}
// 将创建的弹窗容器组件直接append到弹出层DOM中
this._hostDomElement.appendChild(this._getComponentRootNode(componentRef));
// 返回组件的引用
return componentRef;
}
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
portal.setAttachedHost(this);
// If the portal specifies an origin, use that as the logical location of the component
// in the application tree. Otherwise use the location of this PortalHost.
// 如果入口已经有宿主则使用那个宿主
// 否则使用 PortalHost 作为宿主
let viewContainerRef = portal.viewContainerRef != null ?
portal.viewContainerRef :
this._viewContainerRef;
// 在宿主上动态创建组件的代码
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component);
let ref = viewContainerRef.createComponent( // 使用 ViewContainerRef 动态创建组件到当前视图容器(也就是弹窗容器指令)
componentFactory, viewContainerRef.length,
portal.injector || viewContainerRef.parentInjector
);
super.setDisposeFn(() => ref.destroy());
this._portal = portal;
return ref;
}
host: {
'class': 'mat-dialog-container',
'tabindex': '-1',
'[attr.role]': '_config?.role',
'[attr.aria-labelledby]': '_ariaLabelledBy',
'[attr.aria-describedby]': '_config?.ariaDescribedBy || null',
'[@slideDialog]': '_state',
'(@slideDialog.start)': '_onAnimationStart($event)',
'(@slideDialog.done)': '_onAnimationDone($event)',
}
_onAnimationDone(event: AnimationEvent) {
if (event.toState === 'enter') {
this._trapFocus();
} else if (event.toState === 'exit') {
this._restoreFocus();
}
this._animationStateChanged.emit(event);
this._isAnimating = false;
}
constructor(
private _overlayRef: OverlayRef,
private _containerInstance: MatDialogContainer,
public readonly id: string = 'mat-dialog-' + (uniqueId++)
) {
// 添加弹窗开启的订阅 这里的 RxChain 是material2自己对rxjs的工具类封装
RxChain.from(_containerInstance._animationStateChanged)
.call(filter, event => event.phaseName === 'done' && event.toState === 'enter')
.call(first)
.subscribe(() => {
this._afterOpen.next();
this._afterOpen.complete();
});
// 添加弹窗关闭的订阅,并且需要在收到回调后销毁弹窗
RxChain.from(_containerInstance._animationStateChanged)
.call(filter, event => event.phaseName === 'done' && event.toState === 'exit')
.call(first)
.subscribe(() => {
this._overlayRef.dispose();
this._afterClosed.next(this._result);
this._afterClosed.complete();
this.componentInstance = null!;
});
}
/**
* 这个也就是实际使用时的关闭方法
* 所做的事情是添加beforeClose的订阅并执行 _startExitAnimation 以开始关闭动画
* 底层做的事是 改变了弹窗容器中 slideDialog 的状态值
*/
close(dialogResult?: any): void {
this._result = dialogResult; // 把传入的结果赋值给私有变量 _result 以便在上面的 this._afterClosed.next(this._result) 中使用
// Transition the backdrop in parallel to the dialog.
RxChain.from(this._containerInstance._animationStateChanged)
.call(filter, event => event.phaseName === 'start')
.call(first)
.subscribe(() => {
this._beforeClose.next(dialogResult);
this._beforeClose.complete();
this._overlayRef.detachBackdrop();
});
this._containerInstance._startExitAnimation();
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有