Xin-Angular 开发笔记

摘要:近期感觉自己学了很多 angular 的知识,但是十分分散,每次想查看都要去各处找之前实现的代码,准备通过一个项目来回顾并且继续学习新的 Angular 知识。所以参考 Angular Material 官方文档项目,先搭建一个框架,然后将已经学过的技术和未来需要学习都放到上面,并且以此笔记记录开发过程。其中如果有大块知识需要讨论,将单独撰写博文。

计划

本项目力图使用原生 Angular 技术,尽可能将更多的工作放到逻辑层,减少视图层对数据的依赖。同时力求模块组件服务之间依赖关系尽可能简化清晰。

目前进度

基于 Angular CLI 1.6.6, 集成了 Angular material 组件

  1. 独立的顶部菜单,数据和视图分离
  2. 主题切换,独立的主题选择器(material doc 官方的方式,参考博文,编译 SCSS 主题再动态替换 css),另外还使用组件定制主题,参考博文
  3. 语言切换,依赖 ngx-translation,并使用 BabelEditor 编辑语言资源,独立的语言选择器。
  4. Drawer,独立的 Drawer 开关器,使用服务来暴露 drawer 的状态,松耦合更容易使用。
  5. 路由 lazy loading
  6. 日志系统,依赖 ng2-logger,增加 helper 来方便配置,增加全局日志配置,统一管理日志输出的样式。

遇到的问题及解决方案

组件间使用 service 传递数据

参考官方文档 Component-interaction,我们可以使用服务来在 Component 之间传递数据。原理很简单,通过 Observable 变量,需要变更数据的地方在 ObservableSource 数据上调用 next(data),然后接受方只需要监听这个 Observable,就可以收到变化的数据了。

在使用的过程中发现一个问题,就是接收的组件无法收到 Observable 的数据变换,通过大量搜索发现,原来是因为接收的组件所在的模块是一个 Lazy Loading 的模块,所以导致服务的环境是独立,和其他模块不同,

I suspect it’s because lazy loaded module has its own scope of singleton service, means there two instance of your SnackbarService. Try move the service to the highest level module like app module see if that solves the problem.

所以解决方案就是将该服务放在顶层的 AppModule 的 providers 中,这样就可以在同一个 Scope 中了。

同时我们也应该从中了解到,AngularServiceScope 并不是单纯具有的全局性,是有很多条件的,至少现在知道 Lazy ModuleScope 和其父级的 Module 是依赖的。而且需要明白 Service 所处的位置(在 providers 中)决定了 Servicescope

我们进一步查看 NgModule 官方文档,来深入探讨该问题:

Why is a service provided in a lazy-loaded module visible only to that module?

该问题为 NgModule Q&A

Unlike providers of the modules loaded at launch, providers of lazy-loaded modules are module-scoped.

When the Angular router lazy-loads a module, it creates a new execution context. That context has its own injector, which is a direct child of the application injector.

The router adds the lazy module’s providers and the providers of its imported NgModules to this child injector.

These providers are insulated (绝缘的) from changes to application providers with the same lookup token. When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.

更详细的内容还可以看这个介绍 Limiting provider scope by lazy loading modules 以及这个博文

看来 NgModule 的文档还是应该再好好看看。