动手写一个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 一个自定义长度的文本自动换行的函数
Aug 19 Javascript
js 弹出菜单/窗口效果
Oct 30 Javascript
使用mouse事件实现简单的鼠标经过特效
Jan 30 Javascript
JavaScript 模块化编程(笔记)
Apr 08 Javascript
jQuery插件multiScroll实现全屏鼠标滚动切换页面特效
Apr 12 Javascript
jQuery实现可编辑的表格实例讲解(2)
Sep 17 Javascript
20分钟打造属于你的Bootstrap站点
Jul 27 Javascript
利用express启动一个server服务的方法
Sep 17 Javascript
微信小程序websocket实现聊天功能
Mar 30 Javascript
JavaScript中join()、splice()、slice()和split()函数用法示例
Aug 24 Javascript
electron实现静默打印的示例代码
Aug 12 Javascript
12 种使用Vue 的最佳做法
Mar 30 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入门基础之php代码写法
2011/12/30 PHP
Laravel中扩展Memcached缓存驱动实现使用阿里云OCS缓存
2015/02/10 PHP
PHP实现一维数组转二维数组的方法
2015/02/25 PHP
PHP关联数组实现根据元素值删除元素的方法
2015/06/26 PHP
PHP文件操作简单介绍及函数汇总
2020/12/11 PHP
一个轻量级的javascript库 pj介绍
2010/12/19 Javascript
jquery调用asp.net 页面后台的实现代码
2011/04/27 Javascript
Jquery网页出现的乱码问题的三种解决方法
2013/06/30 Javascript
JavaScript获取/更改文本框的值的实例代码
2013/08/02 Javascript
jquery.hotkeys监听键盘按下事件keydown插件
2014/05/11 Javascript
文件上传插件SWFUpload的使用指南
2016/11/29 Javascript
js中删除数组中的某一元素实例(无下标时)
2017/02/28 Javascript
如何使用angularJs
2017/05/08 Javascript
vue实现登陆登出的实现示例
2017/09/15 Javascript
vue全局组件与局部组件使用方法详解
2018/03/29 Javascript
vue-quill-editor+plupload富文本编辑器实例详解
2018/10/19 Javascript
vue与bootstrap实现简单用户信息添加删除功能
2019/02/15 Javascript
vue使用el-upload上传文件及Feign服务间传递文件的方法
2019/03/15 Javascript
python下MySQLdb用法实例分析
2015/06/08 Python
python实现linux下使用xcopy的方法
2015/06/28 Python
使用PyV8在Python爬虫中执行js代码
2017/02/16 Python
详解Python里使用正则表达式的ASCII模式
2017/11/02 Python
Python:slice与indices的用法
2019/11/25 Python
pytorch程序异常后删除占用的显存操作
2020/01/13 Python
python的Jenkins接口调用方式
2020/05/12 Python
python实现感知机模型的示例
2020/09/30 Python
5分钟让你掌握css3阴影、倒影、渐变小技巧(小编推荐)
2016/08/15 HTML / CSS
CSS3制作hover下划线动画
2017/03/27 HTML / CSS
css3旋转木马_动力节点Java学院整理
2017/07/12 HTML / CSS
Unix如何添加新的用户
2014/08/20 面试题
2014大学生职业生涯规划书最新范文
2014/09/13 职场文书
银行柜员优质服务心得体会
2016/01/22 职场文书
SQL实现LeetCode(178.分数排行)
2021/08/04 MySQL
Python实现归一化算法详情
2022/03/18 Python
Android Studio实现带三角函数对数运算功能的高级计算器
2022/05/20 Java/Android
Java实现超大Excel文件解析(XSSF,SXSSF,easyExcel)
2022/07/15 Java/Android