如何實現angular2版本的modal彈框

weixin_34253539發表於2018-01-25

最近看angular2專案程式碼時發現專案中modal的使用形式是,哪裡需要modal就寫在哪裡,modal嵌入在Dom樹中的很深層而不是在直接掛在body下,這樣會導致很大的問題。產生問題原因可以產看該連結:http://web.jobbole.com/92121/

於是就想自己寫一個能直接在掛在body底下的modal。

那麼怎麼實現能?通過傳統component,其存在於component樹中顯然無法隨意改變component在樹中的結構,好在我們有dynamic component,通過它我們能自主建立其例項並自主決定其掛載的位置,比如我們要掛載至body下。

具體實現如下,為了圖方便自己基於jquery和bootstrap3實現(基於原生實現原理相同),原理:動態例項化元件,將元件dom掛至body下。刪除時destroy component ,移除dom

import {
  ComponentFactoryResolver,
  ComponentRef,
  ReflectiveInjector,
  ApplicationRef,
  Injectable,
  EventEmitter,
} from '@angular/core';
@Injectable()
export class ModalService {
  private modals: Modal[] = [];
  constructor(private componentFactoryResolver: ComponentFactoryResolver,
              private applicationRef: ApplicationRef) { }

  create(component) {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
    const injector = ReflectiveInjector.resolveAndCreate([]);
    const componentRef = componentFactory.create(injector);
    this.applicationRef.attachView(componentRef.hostView);
    document.body.appendChild(componentRef.location.nativeElement);
    const modal = new Modal(componentRef);
    this.modals.push(modal);
    return modal;
  }
  destory(modal: Modal) {
    modal.hide();
    this.modals.splice(this.modals.indexOf(modal), 1);
    modal.$el.remove();
    modal.componentRef.destroy();
  }
}

export class Modal {
  $el;
  $modalEl;
  public componentRef;
  public onShown = new EventEmitter();
  public onHidden = new EventEmitter();
  constructor(componentRef) {
    this.$el = $(componentRef.location.nativeElement);
    this.$modalEl = this.$el.find('.modal');
    this.componentRef = componentRef;
    this.$modalEl.on('shown.bs.modal', (e)=>{
      this.onShown.emit(e);
    });
    this.$modalEl.on('hidden.bs.modal',(e)=>{
      this.onHidden.emit(e);
    });
  }
  show() {
    this.$modalEl.modal('show');
  }
  hide() {
    this.$modalEl.modal('hide');
  }
}

使用

 this.modal = this.modal || this.modalService.create(SelectDeviceModalComponent);
    this.modal.show();
    this.modal.onHidden.subscribe((e) => {
      this.modalService.destory(this.modal);
      this.modal = null;
    });

注意由於是基於bootstrap的實現所以。create中傳的元件的html必須是bootstrap的modal形式,例如:

<div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="gridSystemModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="gridSystemModalLabel">Modal title</h4>
      </div>
      <div class="modal-body">
       
      </div>
      <div class="modal-footer">

      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

相關文章