Angular-SCAM concept

更新日期: 2023-01-06阅读: 686标签: Angular

本文开始

在大型的angular Application ,都会使用大量的Module 来将元件需要使用的功能给引用进来,但是,当我们在同一个Module 里面定义多个Component 的时候,就需要从外部引入多个功能进来以让这些Component 都能吃到它们自身需要使用到的功能。

以上这种情况就会导致下面这个问题,假设这个模组有A, B 两个元件,当模组引入A 元件需要使用的功能,但这些功能B 元件都不需要使用,而模组也引入B 元件需要使用的功能,但A 元件都用不到,这样子的情况会导致这个模组要做的事情太杂,且其功能也意义不明。

来举个范例

@NgModule({
  providers: [
    ConfigService, 
    PromotionService, 
    AppService,
  ],
  declarations: [
    StringSlicePipe,
    CustomerFormatterPipe,
    ShoppingCartDealPipe,
    CurrencyFormatterPipe,
    CustomerCardComponent,
    ShoppingCartComponent,
    CustomerPortalComponent,
  ],
})
export class CustomerPortalModule {}

假设今天我们除了在CustomerPortalModule 会需要使用到ShoppingCartComponent 以外,在其他的模组中也会需要使用到ShoppingCartComponent 很自然地我们会写出以下程式码

@NgModule({
  declarations: [
    ShoppingCartComponent,
    AnotherPageComponent,
  ],
})
export class AnotherPageModule {}

Ok,加完了,接下来我们先看看ShoppingCartComponent 的建构式里有注入哪些service ,因为也需要引入进这个模组,如此一来ShoppingCartComponent 才能在这个模组正常运作。

@Component({...})
export class ShoppingCartComponent {
...

  constructor(private ConfigService) {}
...
}

可以看到它有加入ConfigService 这个服务,所以,我们要在AnotherPageModule 引入它

@NgModule({
  providers: [
    ConfigService // 加入 ConfigService
  ],
  declarations: [
    ShoppingCartComponent,
    AnotherPageComponent,
  ],
})

export class AnotherPageModule {}

但是,这样还是无法运作!! 因为ConfigService 自己又引入了PromotionService 这个服务,所以,为了ConfigService 我们要再引入PromotionService,所以,再改写一下AnotherPageModule 

@NgModule({
  providers: [
    ConfigService,
    PromotionService  // 加入 PromotionService
  ],
  declarations: [
    ShoppingCartComponent,
    AnotherPageComponent,
  ],
})
export class AnotherPageModule {}

接着,我们来看看ShoppingCartComponent 的template,发现它还有用一些pipe 的功能,所以,要再引入这些pipe 到模组中

@NgModule({
  providers: [
    ConfigService,
    PromotionService
  ],
  declarations: [
    CurrencyFormatterPipe, // 加入 pipe
    CustomerCardComponent, // 加入 pipe
    ShoppingCartComponent,
    AnotherPageComponent,
  ],
})
export class AnotherPageModule {}

经过以上一连串的引入,有发现了吗?

当我们需要在其他地方使用某个元件的时候,就会要因为该元件有使用和注入的所有功能再次在这个模组再次引入这些功能。

 

巨大的ShareModule 臭味

而以上这样的问题,也就造就了为什么很多专案里面都会使用ShareModule,在这个Module 里面一次引入所有元件需要使用到的功能,然后,在不同的模组间引入ShareModule 以解决以上的问替。

It kinda works. But 有使用过ShareModule 的方法的人应该都知道,这个ShareModule 最终随着专案扩充,会越长越大~

而这个巨大的ShareModule 就会隐隐地飘出bad code 的臭味(因为还是会落入A 模组引入了shareModule,但是shareModule 里有一半以上的功能A 模组可能都不需要使用)~~

而我们就要透过SCAM 这个概念来解决以上这些问题啰~

 

什么是SCAM 样板?

它的全名叫做Single Component Angular Module。

这个样板的概念就是,直接让元件客制化属于它自己的Module 。

Angular 的Module 原本的用意,是用来封装该模组中,所包含的元件彼此之间相关的程式码(eg 元件所需的共用方法),但是,我们用ShareModule 的概念把所有不相关的功能通通引入到同一个模组里面,等于直接抛弃原本Angular 模组的精神。

来个简单的范例

@NgModule({
  declarations: [
    CustomerCardComponent,
    CustomerFormatterPipe
  ],
  exports: [CustomerCardComponent]
})
export class CustomerCardComponentModule {}

以上这个写法是传统的写法,需要什么就全部引入,因为CustomerCardComponent 需要使用CustomerFormatterPipe 所以,需要引用它。

那现在我们把它们拆开来,

Step 1. 为CustomerFormatterPipe 定义属于它自己的Module

@NgModule({
  declarations: [
    CustomerFormatterPipe
  ],
  exports: [CustomerFormatterPipe]
})
export class CustomerFormatterPipeModule {}

Step 2. 在CustomerCardComponentModule 引入CustomerFormatterPipeModule

接下来,改写一下原本在CustomerCardComponentModule 直接引入CustomerFormatterPipe 的写法

@NgModule({
  imports: [
    CustomerFormatterPipeModule 
  ],
  declarations: [
    CustomerCardComponent
  ],
  exports: [CustomerCardComponent]
})
export class CustomerCardComponentModule {}

以上就是SCAM 样板的执行方式。

那我们把以上的执行方式,套用到最一开始的ShoppingCartComponent 的范例

Step 1. 为元件定义属于它自己个Module

@NgModule({
  // I wont bother with these services, as we really should be making them providedIn: 'root'!
  providers: [
    ConfigService, 
    PromotionService,
  ],
  imports: [
    CustomerCardComponentModule,
    CurrencyFormatterPipeModule,
  ],
  declarations: [
    ShoppingCartComponent,
  ],
  export: [ShoppingCartComponent]
})
export class ShoppingCartComponentModule {}

Step 2. 引入ShoppingCartComponentModule 模组到CustomerPortalModule 里

@NgModule({
  imports: [
    ShoppingCartComponentModule // 引入 ShoppingCartComponentModule 
  ],
  declarations: [
    StringSlicePipe,
    CustomerFormatterPipe,
    ShoppingCartDealPipe,
    // CurrencyFormatterPipe, 可以拿掉
    // CustomerCardComponent, 可以拿掉
    // ShoppingCartComponent, 可以拿掉
    CustomerPortalComponent,
  ],
  exports: [CustomerPortalComponent]
})
export class CustomerPortalModule {}

可以看到上面我们透过SCAM 的模板设计方式先建造出属于ShoppingCartComponent 自己的模组后,再直接引入到CustomerPortalModule ,如此一来是不是Module 就可以少写很多额外的程式码,也不用引入东引入西的。

另外,我们在另外一个模组AnotherPageModule 要使用ShoppingCartComponent 也是直接引入ShoppingCartComponentModule 就好,改写如下

@NgModule({
  imports: [
    ShoppingCartComponentModule // 引入 ShoppingCartComponentModule 
  ],
  declarations: [
    AnotherPageComponent,
  ]
})
export class AnotherPageModule {}

是不是模组内部干净多了呢~~

 

PrimeNG UI framework 的SCAM 样板写法

在Angular 专案中,很常用一个叫Primeng 的UI Framework。

有别于这一篇教学文章直接写出一个module.ts 档案,在PrimeNG 里SCAM 样板写法笔者判断应该都是直接将module 定义的内容直接写在各元件的定义档里。

这样一来就不需要用像shareModule 这个一大包的共用Module 了。

来自:https://www.tpisoftware.com/tpu/articleDetails/2894

链接: https://www.fly63.com/article/detial/12308

angular.js和vue.js中实现函数去抖

搜索输入框中,只当用户停止输入后,才进行后续的操作,比如发起Http请求等。本文将分别探讨在angular.js和vue.js中如何实现对用户输入的防抖。

你所要知道的所有关于Angular的变化检测机制

如果想像我一样全面的了解Angular的脏值检测机制,除了浏览源代码之外别无他法,网上可没有太多可用信息。大部分文章都提到,Angular中每个组件都自带一个脏值检测器,但是它们都仅仅停留在脏值检测的策略和案例的使用,并没有做太多的深入。

探索 Angular 使用 ViewContainerRef 操作 DOM

每次我读到 Angular 如何操作 DOM 相关文章时,总会发现这些文章提到 ElementRef、TemplateRef、ViewContainerRef 和其他的类。尽管这些类在 Angular 官方文档或相关文章会有涉及,但是很少会去描述整体思路

解决angularJS解决数据显示闪一下的问题?

使用 angular JS 的时候,把 angularJS 放到文件底部,在渲染页面的时候,会出现闪一下的情况。解决办法:1、使用 ng-cloak ;2、将angular.js的引入放到head前,提前加载;3、使用 ng-bind

Angular HMR(热模块替换)功能实现方法

在使用Angular的时候,希望能像VUE那样,修改代码后浏览器不刷新,页面对应修改的组件自动更新的功能。这个功能的名字时HMR (hot module replace)。稍微研究了一下,发现在angular/cli创建的项目中,实现这个不算太难,步骤如下

Angular 6的新功能,特点介绍

Angular 6目的是为了使Angular变得更小,更快,更易于使用。Angular 6版本更加关注底层框架和工具链,同时加快了工具链在Angular中的运行速度,除此以外,这次更新还包括框架包

angular2及其他项目中遇到的问题和解决方法

Angular2项目日常开发中所遇问题及解决方案记录:angular-cli修改域名及端口号、解决双击变蓝的问题、修改浏览器滚动条的默认样式等等

angular动态绑定样式以及改变UI框架样式的方法

ngClass要绑定的类名会在tr根据数据循环生成html的过程中调用组件中定义的isHideClass方法,并把i(index)带过去让方法使用根据方法逻辑返回的类名去绑定写好的样式

Angularjs的$http异步删除数据详解及实例

这篇文章主要介绍了Angularjs的$http异步删除数据详解及实例的相关资料,这里提供实现思路及实现具体的方法,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。

angularJS自定义服务的几种方式

在angularJS中定义服务共有四种常见的方式:factory,service,provider,constant,value.使用形式的不同:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!