【问题标题】:Angular2, generic overlay component for all other components inside the appAngular2,应用程序内所有其他组件的通用覆盖组件
【发布时间】:2016-10-23 10:05:39
【问题描述】:

我有以下两个组件:

叠加层

@Component({
    selector: 'overlay',
    template: '<div class="check"><ng-content></ng-content></div>'
})
export class Overlay {
    save(params) {
        //bunch of stuff that are commonly used
    }
}

myComponent(还有很多这样的)

@Component({
    selector: 'myComponent',
    directives: [Overlay],
    template: '<overlay><form (ngSubmit)="save({ name: 'sam', lastName: 'jones' })">I'm the component. Click <input type="submit">Here</input> to save me!</form></overlay>'
})
export class MyComponent {

}

这个解决方案在没有错误的情况下不起作用,Angular2 只是跳过了两个组件的初始化。无论如何,我想你明白这里的想法。有一个通用组件需要包装许多其他组件,因此它需要是通用的。它有一个template,所以服务不能完成这项工作。我没有太多使用自定义注释,也许他们可以做这样的事情?关于如何实现这样的功能有什么想法吗?

注意:叠加层包含逻辑和模板,任何其他需要使用它的组件都需要这两者。该模板是一个复杂的模态对话框,其中包含动画、消息、淡入淡出等……在整个解决方案中都很常见。

更新

找到这个:Angular2: progress/loading overlay directive

【问题讨论】:

  • 为什么不使用属性/结构指令?您可以通过将数据绑定到该指令并重用该指令来定制组件的行为
  • @SeyedJalalHosseini 在这种情况下,需要显示和删除引导模式。它有我提到的内容,那么directive 如何存储和显示该内容?

标签: typescript angular


【解决方案1】:

我为这个特定任务创建了一个,并考虑将引导模式嵌入为模板,但遇到了一些问题,例如引导模式中唯一有用的部分就是类名。毫不奇怪,我不想在这个特定任务中使用它,因为我需要区分组件上的窗口模式和进度模式。

叠加层

@Component({
    selector: 'overlay',
    template:
    `<div [ngClass]="isOpen ? 'opened' : 'closed'">
         <div class="modal" role="dialog">
            <div class="modalBody">
                <div *ngIf="isSaving">
                    <span class="text-success text-bold">
                        Saving...
                    </span>
                </div>
                <div *ngIf="isSaved">
                    <span class="text-success text-bold">
                        Saved.
                    </span>
                </div>
            </div>
        </div>
    </div>`,
    styles: [
        '.modal { position:absolute; width: 100%; height: 100%; margin: -30px; background-color: rgba(255, 255, 255, 0.7); z-index: 1000; text-align: center; }',
        '.closed { visibility: hidden; }',
        '.opened { visibility: visible; }',
        '.modalBody { top: 45%; left: 25%; width: 50%; position: absolute; }',
        '.text-bold { font-weight: 800; font-size: 1.5em; }'
    ]
})
export class Overlay implements OnChanges, AfterContentInit {
    @Input() isSaving: boolean = false;
    @Input() isSaved: boolean = false;
    @Input() containerElement: HTMLElement;

    isOpen = false;

    private modalElement;

    constructor(private element: ElementRef, private animationBuilder: AnimationBuilder) { }

    ngOnChanges() {
        if (this.modalElement) {
            if (this.isSaving == true || this.isSaved == true) {
                this.toggleAnimation(true);
            }
            else if (this.isSaving == false && this.isSaved == false) {
                this.toggleAnimation(false);
            }
        }
    }

    ngAfterContentInit() {
        this.containerElement.style.position = 'relative';
        this.modalElement = this.element.nativeElement.querySelector('.modal');
    }

    private toggleAnimation(isOpen) {
        var startCss = { backgroundColor: 'rgba(255, 255, 255, 0)' };
        var endCss = { backgroundColor: 'rgba(255, 255, 255, 0.7)' };

        if (isOpen) {
            this.isOpen = true

            this.animation(
                true,
                this.modalElement,
                400,
                startCss,
                endCss,
                null
            );
        }
        else {
            this.animation(
                isOpen,
                this.modalElement,
                400,
                startCss,
                endCss,
                () => {
                    this.isOpen = false;
                }
            );
        }
    }

    private animation(isStart, element, duration, startCss, endCss, finishedCallback) {
        var animation = this.animationBuilder.css();

        animation.setDuration(duration);

        if (isStart) {
            animation.setFromStyles(startCss).setToStyles(endCss);
        } else {
            animation.setFromStyles(endCss).setToStyles(startCss)
        }

        animation.start(element);

        if (finishedCallback) {
            setTimeout(finishedCallback, duration);
        }
    }
}

用法

照原样,您需要一个相对容器才能让overlay 填充其父容器。 css 肯定需要修改以适应一些场景,例如移动设备和非定位容器。以下是它目前的使用方式:

HTML

<form action="/edit" method="post" #myForm="ngForm" (ngSubmit)="save ajax method that will update the isSaving and isSaved accordingly" novalidate>
    <div style="position: relative;" #overlayContainer>
        <overlay [isSaving]="isSaving" [isSaved]="isSaved" [containerElement]="overlayContainer"></overlay>
    </div>
</form>

保存form 后,overlaycontainerElement 中显示 400 毫秒,然后淡出并隐藏,直到下次尝试保存。 isSavingisSaved 绑定值是希望使用 overlay 的任何组件的责任。

【讨论】:

  • AnimationBuilder 类是从哪里导入的?是“@angular/animations”吗?我收到错误“AnimationBuilder 类型上不存在属性 css”。还是我错过了什么?
【解决方案2】:

好的,也许这不是您问题的直接答案,但从您的评论中我猜您想在您的应用程序中实现模态。 我还没有这样做,但在不久的将来我会这样做(这是我的应用程序要求的一部分)。

首先我不使用引导程序 javascript 因为我已经在使用 angular。您唯一需要的是引导 css

考虑下面的根模板:

 <my-app></my-app>

 <my-modal>
    <div class="modal-container">
       <div class="modal-content">{{modalContent}}</div>
    </div>
 </my-modal>

显示您的模式:全局事件

您可以从任何component 显示您的模态。诀窍是注入modal-service 来发送全局事件。请参阅this 答案以了解其工作原理。

您可以将任何对象发送为event。此事件对象可能包含您的模态内容或key,因此模态component 可以从其他地方获取它。

模态组件

您的ModalComponent 应该订阅该事件。在事件中,您可以通过多种方式显示和隐藏它(模态组件),我相信您知道。使用结构指令是一种方法。

风格

模态框是一个容器 (.modal-container),具有透明背景的 viewportwidthheight。 Modal 的内容 (.modal-content) 是另一个具有固定 widthheightabsolute 位置的容器。如果你想要引导样式,你可以添加它,动画你可以使用angular animations

我目前正在对菜单栏使用类似的方法,效果非常好!!

【讨论】:

  • 干得好,我找到了一个解决方案,我会在完成后发布。更简单、更干净,而且由于各种原因,我将在以后的帖子中提到,我也不一定需要引导模式。
猜你喜欢
  • 1970-01-01
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 2022-06-16
  • 2017-05-09
相关资源
最近更新 更多