一个指令用Angular 2+中的微调器替换加载内容

ans*_*sen 6 angular2-directives angular

在Angular 1中,创建一个用旋转器替换内容的加载指令相当容易,并且使用如下:

<div isLoading="$scope.contentIsLoading"></div>
Run Code Online (Sandbox Code Playgroud)

其中contentHasLoaded是您在数据调用后在控制器中设置的简单布尔值.该指令本身很简单,大部分工作都是在模板中完成的:

<div class="spinner" ng-if="$scope.isLoading"></div>
<div ng-transclude ng-if="!$scope.isLoading"></div>
Run Code Online (Sandbox Code Playgroud)

在Angular 2+中有一种"干净"的方法吗?通过干净我的意思是1)在Angular中,不使用vanilla JS直接操作DOM和2)可以作为现有元素的单个属性实现吗?

我确实看到这篇文章是后备:图像加载指令.但是,它比我想要的更冗长:使用常规组件需要我将所有异步内容包装在新标签中而不是仅添加属性.

我真正想要的是结构指令中的东西(它应该被设计用于"操纵DOM".)然而,我见过的所有例子都是像*ngIf这样隐藏内容的东西,但是不插入新内容.具体而言,结构模板1)可以具有模板,或2)插入组件或3)插入简单的东西<div class="spinner"></div>.到目前为止,这是我最好的尝试:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[loading]',
  inputs: ['loading']
})
export class LoadingDirective {

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
    ) { }

  @Input() set loading (isLoading: boolean) {
    if (isLoading) {
      this.viewContainer.clear();
      // INSERT A COMPONENT, DIV, TEMPLATE, SOMETHING HERE FOR SPINNER
    } else {
      this.viewContainer.clear();
      // If not loading, insert the original content
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

小智 13

这可以在Angular2 +以你所描述的方式完成,你在正确的轨道上.您的结构指令将包含主机元素的模板,您可以注入一个组件来容纳加载图像等.

指令 该指令采用输入参数来指示加载状态.每次设置此输入时,我们都会清除viewcontainer,并根据加载值注入加载组件或主机元素的模板.

@Directive({
  selector: '[apploading]'
})
export class LoadingDirective {
  loadingFactory : ComponentFactory<LoadingComponent>;
  loadingComponent : ComponentRef<LoadingComponent>;

  @Input() 
  set apploading(loading: boolean) {
    this.vcRef.clear();

    if (loading)
    {
      // create and embed an instance of the loading component
      this.loadingComponent = this.vcRef.createComponent(this.loadingFactory);
    }
    else
    {
      // embed the contents of the host template
      this.vcRef.createEmbeddedView(this.templateRef);
    }    
  }

  constructor(private templateRef: TemplateRef<any>, private vcRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) {
    // Create resolver for loading component
    this.loadingFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingComponent);
  }
}
Run Code Online (Sandbox Code Playgroud)

组件 您可以看到除了保留模板之外什么都不做.

@Component({
  selector: 'app-loading',
  template: `<div class="loading">
              <img src="assets/loading.svg" alt="loading">
            </div>`
})
export class LoadingComponent {

  constructor() { }
}
Run Code Online (Sandbox Code Playgroud)

实现 结构指令的用法,绑定到布尔值

<div *apploading="isLoadingBoolean">
  <h3>My content</h3>
  <p>Blah.</p>
</div>
Run Code Online (Sandbox Code Playgroud)

注意:您还需要在ngModule的entryComponents数组中包含LoadingComponent.