动手写一个angular版本的Message组件的方法


Posted in Javascript onDecember 16, 2017

学习一个框架或库的最好方法是看官方文档,并着手去写例子。最近在利用空闲的时间学习angular,那今天就尝试写一个message组件,并通过message服务动态加载message组件。
我所参与的项目基本是用jquery完成的。之前,在项目中自己动手写过一个简单的message插件,样子如下图。

动手写一个angular版本的Message组件的方法

那现在就使用angular(版本5.0.0)来实现message组件。

message组件

message组件要根据传入的类型、消息和duration来显示。创建三个文件:message.component.ts,message.component.html,message.component.css,代码如下。

//message.component.ts
import {Component,Input,OnInit,ChangeDetectionStrategy} from '@angular/core';
import {
  trigger,
  state,
  style,
  transition,
  animate
 } from '@angular/animations';
const mapping={
  success:'glyphicon-ok-sign',
  warning:'glyphicon-exclamation-sign',
  error:'glyphicon-exclamation-sign',
  info:'glyphicon-ok-circle'
}
@Component({
  selector:'upc-ng-message',
  templateUrl:'./message.component.html',
  styleUrls:['./message.component.css'],
  changeDetection:ChangeDetectionStrategy.OnPush
})
export class MessageComponent implements OnInit{
  ngOnInit(): void {
    this.typeClass=['upc-message-' + this.msgType];
    this.typeIconClass=[mapping[this.msgType]];
  }
  @Input() msgType:'success' | 'info' | 'warning' | 'error'='info'

  @Input() payload:string = ''

  private typeClass
  private typeIconClass
}
<!--*message.component.html-->
<div class="upc-message">
    <div class="upc-message-content" [ngClass]="typeClass">
      <i class="glyphicon" [ngClass]="typeIconClass"></i>
      {{payload}}
    </div>
</div>
.upc-message {
  position: fixed;
  z-index: 1999;
  width: 100%;
  top: 36px;
  left: 0;
  pointer-events: none;
  padding: 8px;
  text-align: center;
 }
 .upc-message i {
   margin-right: 8px;
   font-size: 14px;
   top: 1px;
   position: relative;
 }
 .upc-message-success i {
   color: green;
 }
 .upc-message-warning i {
   color: yellow;
 }
 .upc-message-error i {
   color: red;
 }
 .upc-message-content {
   padding: 8px 16px;
   -ms-border-radius: 4px;
   border-radius: 4px;
   -webkit-box-shadow: 0 2px 8px #000000;
   -ms-box-shadow: 0 2px 8px #000000;
   box-shadow: 0 2px 8px #000000;
   box-shadow: 0 2px 8px rgba(0,0,0,.2);
   background: #fff;
   display: inline-block;
   pointer-events: all;
 }

ComponentLoader

通过官方文档动态组件一节,可以了解动态创建组件需要通过ComponentFactoryResolver来完成。使用ComponentFactoryResolver创建ComponentFactory,再通过ComponentFactory的create方法创建组件。看官方文档中API的说明,ComponentFactory的create方法至少需要一个injector参数,而injector的创建在文档中也有提到,其中参数providers为需要注入的类。再梳理下整个过程:

  1. 提供providers
  2. 创建Injector实例
  3. 创建ComponetFactory
  4. 使用ComponetFactory创建ComponentRef
//ComponentFactory的create方法
create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any, ngModule?: NgModuleRef<any>): ComponentRef<C>

//使用Injector的create创建injector实例
static create(providers: StaticProvider[], parent?: Injector): Injector

为了代码的复用,这里创建通用的loader类来完成组件的动态创建。其中,attch方法用于初始化ComponetFactory(参数为组件类型);to方法用于标识组件的父容器;provider方法用于初始化可注入的类;create方法用于创建组件并手动变更检测;remove方法用于移除组件。

import {
  ComponentFactoryResolver,
  ComponentFactory,
  ComponentRef,
  Type,
  Injector,
  Provider,
  ElementRef
} from '@angular/core';
export class ComponentLoader<T>{
  constructor(private _cfr: ComponentFactoryResolver,
    private _injector: Injector) {
  }
  private _componentFactory: ComponentFactory<T>
  attch(componentType: Type<T>): ComponentLoader<T> {
    this._componentFactory = this._cfr.resolveComponentFactory<T>(componentType);
    return this;
  }
  private _parent: Element
  to(parent: string | ElementRef): ComponentLoader<T> {
    if (parent instanceof ElementRef) {
      this._parent = parent.nativeElement;
    } else {
      this._parent = document.querySelector(parent);
    }

    return this;
  }
  private _providers: Provider[] = [];
  provider(provider: Provider) {
    this._providers.push(provider);
  }
  create(opts: {}): ComponentRef<T> {
    const injector = Injector.create(this._providers as any[], this._injector);
    const componentRef = this._componentFactory.create(injector);
    Object.assign(componentRef.instance, opts);
    if (this._parent) {
      this._parent.appendChild(componentRef.location.nativeElement);
    }
    componentRef.changeDetectorRef.markForCheck();
    componentRef.changeDetectorRef.detectChanges();
    return componentRef;
  }
  remove(ref:ComponentRef<T>){
    if(this._parent){
      this._parent.removeChild(ref.location.nativeElement)
    }
    ref=null;
  }
}

同时,为了便于loader的创建,再创建LoaderFactory类,代码如下:

import {
  ComponentFactoryResolver,
  Injector,
  Injectable,
  ElementRef
} from '@angular/core';
import { ComponentLoader } from './component-loader.class';

@Injectable()
export class ComponentLoaderFactory {
  constructor(private _injector: Injector,
    private _cfr: ComponentFactoryResolver) {

  }

  create<T>(): ComponentLoader<T> {
    return new ComponentLoader(this._cfr, this._injector);
  }
}

message service

message service提供显示message的API,代码如下:

import {Injectable,Injector} from '@angular/core';
import { ComponentLoaderFactory } from '../component-loader/component-loader.factory';
import {MessageComponent} from './message.component';
import {ComponentLoader} from '../component-loader/component-loader.class';

@Injectable()
export class MessageService{
  constructor(private _clf:ComponentLoaderFactory,private _injector:Injector){
    this.loader=this._clf.create<MessageComponent>();
  }
  private loader:ComponentLoader<MessageComponent>
  private createMessage(t,c,duration=2000){
    this.loader.attch(MessageComponent).to('body');
    const opts = {
      msgType: t,
      payload:c
    };
    const ref = this.loader.create(opts);
    ref.changeDetectorRef.markForCheck();
    ref.changeDetectorRef.detectChanges();
    let self=this;
    let st = setTimeout(() => {
      self.loader.remove(ref);
    }, duration);
  }
  public info(payload,duration?) {
    this.createMessage('info',payload,duration);
  }
  public success(payload,duration?) {
    this.createMessage('success',payload,duration);
  }
  public error(payload,duration?) {
    this.createMessage('error',payload,duration);
  }
  public warning(payload,duration?) {
    this.createMessage('warning',payload,duration);
  }
}

message.module

最后,增加message.module.ts。记得要把动态创建的组件添加到entryComponents数组中。

import {NgModule} from '@angular/core';
import { CommonModule } from '@angular/common';
import {MessageComponent} from './message.component';
import {MessageService} from './message.service';
import {ComponentLoaderFactory} from '../component-loader/component-loader.factory';

@NgModule({
  imports:[CommonModule],
  declarations:[MessageComponent],
  providers:[MessageService,ComponentLoaderFactory],
  entryComponents:[MessageComponent],
  exports:[MessageComponent]
})
export class MessageModule{
}

使用方法

注入MessageService,调用API使用Message组件。

this._msgService.success('成功了!');

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
游戏人文件夹程序 ver 3.0
Jul 14 Javascript
Iframe thickbox2.0使用的方法
Mar 05 Javascript
js自动闭合html标签(自动补全html标记)
Oct 04 Javascript
JS调试必备的5个debug技巧
Mar 07 Javascript
详解JavaScript中的forEach()方法的使用
Jun 08 Javascript
js如何打印object对象
Oct 16 Javascript
全面解析Bootstrap中transition、affix的使用方法
May 30 Javascript
Javascrip实现文字跳动特效
Nov 27 Javascript
js实现仿购物车加减效果
Mar 01 Javascript
layer弹出层父子页面事件相互调用方法
Aug 17 Javascript
微信小程序自定义弹出模态框禁止底部滚动功能
Mar 09 Javascript
bootstrap-closable-tab可实现关闭的tab标签页插件
Aug 09 Javascript
EasyUI的DataGrid绑定Json数据源的示例代码
Dec 16 #Javascript
使用Electron构建React+Webpack桌面应用的方法
Dec 15 #Javascript
vue给input file绑定函数获取当前上传的对象完美实现方法
Dec 15 #Javascript
微信小程序左右滑动的实现代码
Dec 15 #Javascript
浅析JavaScript中的特殊数据类型
Dec 15 #Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
Dec 15 #Javascript
微信小程序使用request网络请求操作实例
Dec 15 #Javascript
You might like
基于PHP导出Excel的小经验 完美解决乱码问题
2013/06/10 PHP
php中__toString()方法用法示例
2016/12/07 PHP
javascript中巧用“闭包”实现程序的暂停执行功能
2007/04/04 Javascript
javascript网页关键字高亮代码
2008/07/30 Javascript
jQuery 扩展对input的一些操作方法
2009/10/30 Javascript
你必须知道的Javascript知识点之&quot;深入理解作用域链&quot;的介绍
2013/04/23 Javascript
js判断当页面无法回退时关闭网页否则就history.go(-1)
2014/08/07 Javascript
js和jquery实现监听键盘事件示例代码
2020/06/24 Javascript
EasyUI 中combotree 默认不能选择父节点的实现方法
2016/11/07 Javascript
web打印小结
2017/01/11 Javascript
微信小程序 PHP生成带参数二维码
2017/02/21 Javascript
jQuery自定义图片上传插件实例代码
2017/04/04 jQuery
express+mockjs实现模拟后台数据发送功能
2018/01/07 Javascript
vue请求数据的三种方式
2020/03/04 Javascript
Python StringIO模块实现在内存缓冲区中读写数据
2015/04/08 Python
python实现在windows下操作word的方法
2015/04/28 Python
numpy matrix和array的乘和加实例
2018/06/28 Python
python+pyqt5实现图片批量缩放工具
2019/03/18 Python
python算法题 链表反转详解
2019/07/02 Python
python yield关键词案例测试
2019/10/15 Python
ASP.NET Core中的配置详解
2021/02/05 Python
联想新加坡官方网站:Lenovo Singapore
2017/10/24 全球购物
英国信箱在线鲜花速递公司:Bloom & Wild
2019/03/10 全球购物
Richards网上商店:当代时尚,遍布巴西
2019/11/03 全球购物
巴西备受欢迎的服装和生活方式品牌:FARM Rio
2020/02/04 全球购物
Sahajan美国:阿育吠陀护肤品牌
2021/01/09 全球购物
自我评价是什么
2014/01/04 职场文书
遵纪守法演讲稿
2014/05/23 职场文书
法人委托书范本格式
2014/09/15 职场文书
迎国庆横幅标语
2014/10/08 职场文书
后进基层党组织整改方案
2014/10/25 职场文书
秋菊打官司观后感
2015/06/03 职场文书
2016年学校党支部创先争优活动总结
2016/04/05 职场文书
如何写好闭幕词
2019/04/02 职场文书
读鲁迅先生的经典名言
2019/08/20 职场文书
Vue实现tab导航栏并支持左右滑动功能
2021/06/28 Vue.js