动手写一个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 相关文章推荐
javascript函数中参数传递问题示例探讨
Jul 31 Javascript
初识Node.js
Sep 03 Javascript
JavaScript charCodeAt方法入门实例(用于取得指定位置字符的Unicode编码)
Oct 17 Javascript
js实现防止被iframe的方法
Jul 03 Javascript
完善的jquery处理机制
Feb 21 Javascript
JS实战篇之收缩菜单表单布局
Dec 10 Javascript
jQuery鼠标悬停内容动画切换效果
Apr 27 jQuery
angularJS 发起$http.post和$http.get请求的实现方法
May 18 Javascript
angular2 ng build部署后base文件路径问题详细解答
Jul 15 Javascript
vue-router项目实战总结篇
Feb 11 Javascript
微信公众号平台接口开发 获取access_token过程解析
Aug 14 Javascript
JavaScript中的宏任务和微任务详情
Nov 27 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教程孙仲岳主讲
2008/01/07 PHP
jQuery 使用手册(六)
2009/09/23 Javascript
jQuery设置与获取HTML,文本和值的简单实例
2014/02/26 Javascript
使用node.js 制作网站前台后台
2014/11/13 Javascript
JavaScript截断字符串的方法
2015/07/15 Javascript
Node.js实用代码段之正确拼接Buffer
2016/03/17 Javascript
JS模拟简易滚动条效果代码(附demo源码)
2016/04/05 Javascript
jQuery EasyUI Tab 选项卡问题小结
2016/08/16 Javascript
BootStrap中按钮点击后被禁用按钮的最佳实现方法
2016/09/23 Javascript
jQuery实现验证码功能
2017/03/17 Javascript
webpack 1.x升级过程中的踩坑总结大全
2017/08/09 Javascript
vue 表单输入格式化中文输入法异常问题
2018/05/30 Javascript
animate.css在vue项目中的使用教程
2018/08/05 Javascript
20个必会的JavaScript面试题(小结)
2019/07/02 Javascript
vue element ui validate 主动触发错误提示操作
2020/09/21 Javascript
10个易被忽视但应掌握的Python基本用法
2015/04/01 Python
Python装饰器的执行过程实例分析
2018/06/04 Python
Flask框架Flask-Principal基本用法实例分析
2018/07/23 Python
python实现泊松图像融合
2018/07/26 Python
TensorFlow卷积神经网络之使用训练好的模型识别猫狗图片
2019/03/14 Python
Python Web静态服务器非堵塞模式实现方法示例
2019/11/21 Python
matplotlib图例legend语法及设置的方法
2020/07/28 Python
使用CSS3制作饼状旋转载入效果的实例
2015/06/23 HTML / CSS
canvas实现圆绘制的示例代码
2019/09/11 HTML / CSS
Charlotte Tilbury澳大利亚官网:英国美妆品牌
2018/10/05 全球购物
美国手工艺品市场的领导者:Annie’s
2019/04/04 全球购物
世界上最大的乐谱选择:Sheet Music Plus
2020/01/18 全球购物
俄罗斯电子产品在线商店:UltraTrade
2020/01/30 全球购物
澳大利亚头发和美容产品购物网站:OZ Hair & Beauty
2020/03/27 全球购物
毕业生精彩的自我评价分享
2013/10/06 职场文书
旅游管理专业个人求职信范文
2013/12/24 职场文书
触摸春天教学反思
2014/02/03 职场文书
售后服务承诺书范文
2014/03/26 职场文书
股票投资建议书
2014/05/19 职场文书
建筑技术负责人岗位职责
2015/04/13 职场文书
优秀范文:《但愿人长久》教学反思3篇
2019/10/24 职场文书