动手写一个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 相关文章推荐
JS保留小数点(四舍五入、四舍六入)实现思路及实例
Apr 25 Javascript
javascript动态添加样式(行内式/嵌入式/外链式等规则)
Jun 24 Javascript
jquery $(&quot;#variable&quot;) 循环改变variable的值示例
Feb 23 Javascript
jQuery学习笔记之jQuery构建函数的7种方法
Jun 03 Javascript
Javascript中call与apply的学习笔记
Sep 22 Javascript
javascritp添加url参数将参数加入到url中
Sep 25 Javascript
jQuery Chart图表制作组件Highcharts用法详解
Jun 01 Javascript
H5移动端图片压缩上传开发流程
Nov 09 Javascript
原JS实现banner图的常用功能
Jun 12 Javascript
vue resource post请求时遇到的坑
Oct 19 Javascript
记录vue做微信自定义分享的一些问题
Sep 12 Javascript
在vue-cli创建的项目中使用sass操作
Aug 10 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
用cookies来跟踪识别用户
2006/10/09 PHP
javascript 小型动画组件与实现代码
2010/06/02 PHP
PHP目录操作实例总结
2016/09/27 PHP
自动完成JS类(纯JS, Ajax模式)
2009/03/12 Javascript
jquery+ashx无刷新GridView数据显示插件(实现分页、排序、过滤功能)
2010/04/25 Javascript
jQuery 追加元素的方法如append、prepend、before
2014/01/16 Javascript
js获取 type=radio 值的方法
2014/05/09 Javascript
jQuery验证元素是否为空的两种常用方法
2015/03/17 Javascript
jQuery同步提交示例代码
2015/12/12 Javascript
基于JavaScript的操作系统你听说过吗?
2016/01/28 Javascript
更高效的使用JQuery 这里总结了8个小技巧
2016/04/13 Javascript
在javascript中创建对象的各种模式解析
2016/05/16 Javascript
HTML中setCapture、releaseCapture 使用方法浅析
2016/09/25 Javascript
JavaScript中访问id对象 属性的方式访问属性(实例代码)
2016/10/28 Javascript
webpack常用配置项配置文件介绍
2016/11/07 Javascript
微信小程序 详解页面跳转与返回并回传数据
2017/02/13 Javascript
JavaScript创建对象方法实例小结
2018/09/03 Javascript
layui prompt 设置允许空白提交的方法
2019/09/24 Javascript
Python中List.index()方法的使用教程
2015/05/20 Python
详解Python中 sys.argv[]的用法简明解释
2017/12/20 Python
利用python如何处理百万条数据(适用java新手)
2018/06/06 Python
计算机二级python学习教程(2) python语言基本语法元素
2019/05/16 Python
Python数据可视化图实现过程详解
2020/06/12 Python
python excel多行合并的方法
2020/12/09 Python
智利最大的网上商店:Linio智利
2016/11/24 全球购物
德国最大的服装、鞋子和配件在线商店之一:Outfits24
2019/07/23 全球购物
英国最大的在线亚洲杂货店:Red Rickshaw
2020/03/22 全球购物
深圳-东方伟业笔试部分
2015/02/11 面试题
继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么?
2015/11/18 面试题
医药工作岗位求职信分享
2013/12/31 职场文书
男方父母婚礼答谢词
2014/01/25 职场文书
和解协议书
2014/04/16 职场文书
秋季运动会广播稿(30篇)
2014/09/13 职场文书
学生抄作业检讨书(2篇)
2014/10/17 职场文书
居委会工作总结2015
2015/05/18 职场文书
Spring Boot 实现 WebSocket
2022/04/30 Java/Android