Angular依赖注入-Dependency Injection

2018年继续来搞Angular!

什么是依赖注入?

根据维基百科,依赖注入(Dependency Injection)是种解决项目依赖性的设计模式, 好处有大致以下几点:

  • 各模块间的解耦
  • 代码容易维护
  • 开发者无需关注依赖的生产过程,拿来即用

Angular中的DI

Angular的依赖注入有三个重要概念:

  • 注入器(Injector)
  • Provider
  • 依赖(Dependence)

注入器连接了调用方和提供方,使得开发人员很轻松的实现依赖注入。(注:Angular框架已经实现了注入器的生成和调用,并不需要开发者去实现)

注入服务

  1. 通过import导入被依赖对象的服务
  2. Angular读取 @Component@Injectable@Module 装饰器里providers元数据
  3. 在组件构造函数中声明

这样几步,此组件及其子组件都能共享根组件创建的实例,如果子组件或模块不想复用从根组件获取的服务,可以在自己的注入器中重新配置注入(层级注入)。

需要注意的是:

  • Angular没有模块级别作用域,只有程序级和组件级作用域
  • 对于不同的执行上下文,有着不同的注入器,并且执行上下文中的每个依赖对象都是单例的
  • 后面初始化的服务会覆盖前面初始化的服务
  • 由于组件本身是一个类,类有继承关系,但是派生类组件不能继承父类组件的注入器,二者的注入器对象并没有关联,需要使用 super() 将对应的注入服务传递到父类
  • @Host@Optional等装饰器的巧妙使用会带来意想不到的惊喜

Provider

Provider这种设计模式由来已久,在前后台各种技术领域中被广泛使用。它藐视了注入器如何初始化Token所对应的依赖服务,最终注入到组件或者其他服务中。

Provider注册方式

  • 类Provider
    对于调用者来说,业务代码和接口没有改变,从而带来极大的便利
    {provider: Render, useClass: DomRender} //DOM渲染方式
    //{provider: Render, useClass: CanvasRender} //Canvas渲染方式
    //{provider: Render, useClass: ServerRender} //服务端渲染方式
    
  • 值Provider
    实际项目中,以来的对象不一定是类
    {provider: 'name', useValue: 'William Jing'}
    
  • 别名Provider
    实现多个依赖,一个对象实例的所用,例如为了让新旧服务同时可用,新服务兼容老服务,可以使用此种注册方式
    {provider: NewService, useClass: NewService}
    {provider: OldService, useExisting: NewService}
    
  • 工厂Provider
    有时候依赖对象是动态变化的,可能需要环境、执行权限来生成,工厂Provider可以提供解决这个问题,通过暴露一个工厂方法,返回一个最终的依赖对象
    let contactServiceFactory = (_logger: LoggerService, _userService: UserService) =>{
    return new contactService(_logger, _userService.user.isAuthorized)
    }
    
    export let contactServiceProvider = {
    provider: ContactService,
    userFactory: contactServiceFactory,
    deps: [LoggerService, UserService]
    };
    
Angular生命周期钩子

🎅🎅🎅提前祝Merry Xmas🎅🎅🎅

简介

Angular内部管理组件或指令的生命周期,给我们提供了一些接口(这些接口被称为生命周期钩子)来在允许开发者在这些事件触发时,执行相应的回调函数。

Angular一共提供了8个生命周期钩子接口,每个接口有一个唯一的前面加上‘ng’的方法,开发者可以根据实际情况实现其中的一个或者几个来对生命周期的各个阶段进行自定义处理。

图示

下图是Angular钩子方法执行顺序

hooks-in-sequence

钩子方法

  • ngOnChanges()
    首次调用发生在ngOnInit之前,并且,当且仅当组件输入数据变化时被调用,输入数据指的是通过@Input装饰器显示指定的那些变量。
  • ngOnInit()
    创建组件之后立刻调用,经常会使用ngOnInit获取数据。
  • ngDoCheck()
    用于变化监测那些Angular忽略的更改,每次变化监测发生时被调用
  • ngAfterContentInit()
    在组件中使用自定义内容的情况下在第一次ngDoCheck执行后调用,只执行一次
  • ngAfterContentChecked()
    Angular将外部内容嵌入到组件视图后,每次变化监测都会调用ngAfterContentChecked
  • ngAfterViewInit()
    Angular创建了组件的视图以及其子视图之后被调用
  • ngAfterViewChecked()
    视图以及其子视图第一次初始化之后和每次变化监测时被调用
  • ngOnDestroy()
    组件消失之前调用。根据官方文档描述,这里是用来释放那些不会被垃圾收集器自动回收的各类资源的地方。 取消那些对可观察对象和DOM事件的订阅。停止定时器。注销该指令曾注册到全局服务或应用级服务中的各种回调函数。 如果不这么做,就会有导致内存泄露的风险。

注意事项

  • constructor并不是生命周期钩子,而是Class级别的构造函数,constructor总是在所有钩子函数执行前执行
  • 接口是可选的,也就是说不必在Component或Directive后面加上implements…但是,官方还是强烈建开发者在指定类中添加接口以获得强类型和IDE编辑器带来的好处
  • 有的组件还提供了自己特有的生命周期钩子
  • 可能有人会问,为什么不在constructor里获取数据?是因为构造函数做的事应该尽可能简单,比如变量的初始化,不应该负责组件里的内容
  • 绝大多数情况下ngDoCheck和ngOnChanges不应该一起使用
  • ngDoCheck要慎用,因为每个检测周期内,无论数值是否发生变化,ngDoCheck都会被调用,导致调用非常频繁,所以我们的实现要必须非常轻量级
  • ngOnChanges如果输入属性是对象的话,只会检测对象的引用是否变化,而不会去监测对象属性的变化
  • AfterContent和AfterView一共4个钩子是组件专属的,不适用于指令

参考链接

中文官方文档

在线例子

万丈高楼平地起

趁今日闲暇时刻,来给当前的自己“存个档”。

领悟

最开始我立下flag称要写一个关于Angular的技术总结,两周一更新?哈哈哈哈哈,很明显,现在没有实现,打脸啪啪响?ionic框架做一个App?又打脸啪啪响? 其实不然,正是因为最近自己领悟到了–基本功才是硬道理。

很明显的例子,在我用ionic做App的时候,我十分依赖官方的组件,显然官方的组件是不够支撑起所有的需求,这时候如何“创造”一个组件就成了我的大难题。由于缺乏CSS的知识,我只能照猫画虎,生搬硬套,做出来的东西毫无条理性。还有,作为刚入行的新人,我是多么希望能有一位资深的“大佬”来带我们飞啊,但是我并没有在我的周围找到这样一个人。

前端,任重道远

所以,靠谁也不如靠自己!我在学Angular和ionic这种流行框架的同时(放心,Angular还会更新的,App也会做完的(^__^)),我还在追赶前端知识,犀牛书和H5&CSS3从入门到精(fàng)通(qì),不得不说,淘宝团队翻译的犀牛书真是精品,使我受益匪浅,而H5和CSS3的诸多高级玩法也让我练练发出“我屮艸芔茻,这也行”。

废话不多说了,希望自己尽快掌握并精通“前端三板斧”,走向前端大神之路。

基于Ionic3的Node.js中文社区客户端

是不是好久没更新博客了?

是因为我在“练功“–最近在弄一个开源项目:为Nodejs中文社区做一个第三方App,GitHub Repo->CNode-ionic,希望有志同道合的小伙伴多多提建议。

目前实现的功能有:(截止2017年10月9日)

  • 话题展示
  • 话题详情
  • 下拉刷新
  • Loading More

正在进行

  • 3D Touch
  • 扫码登陆
  • 个人信息展示
  • 评论点赞和互动
  • 本地缓存
Angular核心概念之组件(Component)

师者,所以传道受业解惑也。

在今天这个特殊的日子,向所有人民教师说声:你们辛苦了,教师节快乐。(^__^)

论Component的重要性

敲黑板,组件这一块是Angular最重要的部分,没有之一!!!

谈到组件化,必须先提起模块化。Node.js中的模块就是一个文件,通过import的方式来进行模块或者资源的加载,Angular与NOde.js类似。在早期的模块化工具中,多数只对JS文件做了处理,缺少对HTML和CSS的管理。后来形成的按模块划分的概念,相对传统的按资源目录划分的方式,按照逻辑来划分显得更加合理,让模块更加独立,方便维护。

我的理解:前端的组件就是为了实现同一个业务逻辑的代码文件的组合。

@Component

Angular用@Component来定义一个类作为Angular的组件。

最常用的元数据有以下几个:

  • selector:在HTML模板中标识此组件的CSS选择器
  • styleUrls:指定此组件所需要的CSS文件路径(一个数组)
  • templateUrl:指定此组件HTML模板文件路径

还有几个不是很常用的,但是要了解一下:

  • animations:标明此组件的动画效果
  • providers:为此组件注入Service数组(包括子组件)
  • styles:此组件的CSS样式
  • template:此组件的HTML模板 以上两个元数据不建议使用,因为他们是明文固定的写在这个文件里面,不利于复用和维护,建议使用常用的以文件引用的形式。

组件基础

每个组件都有一个模板,Angular才能将组件内容渲染到DOM上,这个DOM元素叫宿主元素。组件可以与宿主元素进行交互,包括:

  • 显示数据:使用插值语法(双大括号)来显示组件的数据
  • 双向数据绑定:便控制用户输入
    [{ngModel}]=property
    
  • 监听宿主元素时间以及调用组件方法:监听click事件,触发组件类中特定函数
    <i (click)="someFun()"></i>
    

    Angular和AngularJS最大的不同就是Angular不再默认双向数据绑定,而是又额外增加了属性以及事件绑定,为交互增加了更多的选择。

组件一般不是单独存在的,而是通过与其他组件协调合作的,然后把他们封装在模块中。模块是组件之上的一层抽象。

未完待续…

组件交互

组件生命周期