From 2f04b7759a772a59da3dad5f10835d10720d1117 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 16:27:52 +0800 Subject: [PATCH 01/20] [article] adds simple-accordion-reactive --- src/app/_shared/api/articles/index.ts | 9 + .../simple-accordion-reactive/_index.md | 215 ++++++++++++++++++ .../screen-shot-r.png | Bin 0 -> 9699 bytes 3 files changed, 224 insertions(+) create mode 100644 src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md create mode 100644 src/app/_shared/api/articles/timliu/simple-accordion-reactive/screen-shot-r.png diff --git a/src/app/_shared/api/articles/index.ts b/src/app/_shared/api/articles/index.ts index 7d3e517..7e6278f 100644 --- a/src/app/_shared/api/articles/index.ts +++ b/src/app/_shared/api/articles/index.ts @@ -3,6 +3,15 @@ import {Article} from '../../models/article'; import {Observable} from 'rxjs/Observable'; const items: Article[] = [ + { + id: '使用 Angular 2 制作简单的 Accordionr 组件 - Model Driven', + title: '使用 Angular 2 制作简单的 Accordionr 组件 - Model Driven', + summary: 'Accordion 后面加一个 r 是几个意思?', + content: require('./timliu/simple-accordion-reactive/_index.md'), + first: true, + tags: ['Angular'], + authors: ['timliu'], + }, { id: 'Angular2中的StructuralDirective', title: 'Angular 2 中的 Sturctural Directive', diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md new file mode 100644 index 0000000..dbc48f0 --- /dev/null +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -0,0 +1,215 @@ +# 使用 Angular 2 制作简单的 Accordionr 组件 - Model Driven + +## 写作原因 +Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会不会好一些?设个小目标吧 -- 比如,制作一个 Accordionr 组件。 +我们知道,Angular 的 form 有两种: +- [template driven form](https://scotch.io/tutorials/using-angular-2s-template-driven-forms),几乎可以把所有的数据和逻辑(比如 validation)都放在 template 里; +- [model driven form](https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol)(或者叫 reactive form),template 很简单,数据和逻辑放在 model 里。 + +组件的制作也可以参照这两种不同的思路。本篇是一个系列的下集,即按照 model driven 思路,应用 Angular 2 制作一个 Accordionr 组件。而上集应用了 template driven 思路。 + +## 读者指引 +- 笔者的偏见:model driven 大法好。仅与上集比较'代码长度'这一项,大家就可以得出结论了。 + +- 本文涉及到的知识点: + - NG2 - [模板语法](https://angular.cn/docs/ts/latest/guide/template-syntax.html)。 + - NG2 - ngFor 的展开写法(模板语法的一小部分)(参见 trotyl 的《[Angular 2 中的 Sturctural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective)》): + 一般我们都是写 `
...
`,展开后是 + ```html + + ``` + 上面的代码会将 `.card` 按 panel 循环。这里只有 `.card` 一个元素。如果我们需要同时循环多于一个元素的时候,`*ngFor` 这样含有星号的写法就行不通了,只能使用展开写法,即 + ```html + + ``` + +- 文章使用 angular-cli 的 [generate 指令](https://github.com/angular/angular-cli#generating-components-directives-pipes-and-services)(简写为 `ng g`)来生成基础代码。 + +- 相应代码可以在[这个 Repo](https://github.com/rxjs-space/try-out-u/tree/master/src/app/tl-ui/tl-accordionr) 找到。 + +## 小目标 +我们希望呈现的效果是: +![页面显示](./screen-shot-r.png) +(这个 R 是 Reactive 的意思,Reactive 是 model driven 的意思,大家别误会。) 初始显示 content0;点击 title1,展开 content1,收起 content0;点击 title2,什么也不做,因为 panel2 是 disabled。 + +这背后是一个 accordionr (最后有个 r) component,另外需要 app.component 提供数据,`Panel` interface 在 accordionr 组件目录里设定。 +```html + + +``` + +```ts +// app.component.ts +export class AppComponent { + private panels: Panel[] = [ + {title: 'Fancy title0 ★', content: 'content0', expanded: true}, + {title: 'title1', content: 'content1'}, + {title: 'title2', content: 'content2', disabled: true}, ]; } +``` +即 accordionr component 负责根据 `@Input() panels` 来显示。 + +几点不那么重要的旁注: +- tl 是前缀,前缀可以是随便什么。 +- expandedOneOnly 是用来初始化的,后面具体说明其功能。 +- title 和 content 可以是 html 代码,比如 `AppComponent.panels[0].title`。 +- 这里不讨论上面的这样的组件结构是否是最优的、是否应该使用“结构 directive”等等,只以实现这个写法为努力方向。 + +## 代码编写 + +### 脚手架搭建(生成基础代码) +我们需要的组成部分包括:accordionr component、config service,还有一个 interface 文件。 +``` +> ng g module tl-accordionr +... (生成 TlAccordionrModule 以及 TlAccordionrComponent) +> ng g service tl-accordionr/tl-accordionr-config +> (假设当前目录为 app)touch tl-accordionr/tl-accordionr.interface.ts +``` +然后在 TlAccordionrModule 里,加上 `exports: [TlAccordionrComponent]`,在 app.module 里加上 `imports: [TlAccordionrModule]`,就可以开始在 app.component.html 里面使用 tl-accordionr 标签了。 +生成 TlAccordionrModule 这个 ngModule 的目的是:预留 provider 位置,方便以后配置全局变量,比如要求 app 里所有的 accordionr 都是怎么怎么样的。 + +### 实现 accordionr 组件显示 panels +```ts +// tl-accordionr.component.ts +export class TlAccordionrComponent { + @Input() private panels: Panel[] = []; } +``` + +```html + +
+ +
+``` +(role 和 class 配合 bootstrap 使用)这样,在 app.component.ts 里定义的 panels 就都显示出来了,一视同仁,不论 expanded、disabled。 + +### 实现按 expanded、disabled 设置来显示 panels +- 需求一:可以按照 app.component.ts 里定义的 expanded、disabled 来初始化 panels; +- 需求二:点击 title后,toggle content; +- 需求三:如果是 disaled panel,不渲染 content。 + +```html + + +
+``` + +```ts +// tl-accordionr.component.ts +export class TlAccordionrComponent { + ... + onTitleClick(panel: Panel) { + if (!panel.disabled) { + panel.expanded = !panel.expanded; // 需求二 + } }} +``` + +### 实现 expandOneOnly +如果 accordionr 的 expandOneOnly 属性为 true,那么同一时间只允许有一个 panel 是展开的。 +- 需求四:accordionr component 记录了'点击之前展开着的 panel'; +- 需求五:在点击某个 title 以后,accordionr component 对比 '被点击 panel' 与'点击之前展开着的 panel',如果不相同,收起 '点击之前展开着的 panel',并重置 '点击之前展开着的 panel'。 + +```ts +// tl-accordionr.component.ts +export class TlAccordionrComponent implements OnInit { + @Input() private expandOneOnly: boolean = false; + ... + private lastExpandedPanel: Panel; // 需求四 + + ngOnInit() { // init lastExpandedPanel + this.lastExpandedPanel = this.panels.filter(panel => panel.expanded)[0]; } // 需求四 + + onTitleClick(panel: Panel) { + if (!panel.disabled) { + ... + if (this.lastExpandedPanel !== panel && this.expandOneOnly) { // 需求五 + this.lastExpandedPanel.expanded = false; + this.lastExpandedPanel = panel; + } }}} +``` + +### 实现全局配置 app 内所有 accordionr +```ts +// tl-accordionr-config.service.ts +@Injectable() +export class TlAccordionrConfigService { + expandOneOnly = false; } + +// tl-accordionr.module.ts +export class TlAccordionrModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: TlAccordionrModule, + providers: [TlAccordionrConfigService] }}} + +// tl-accordionr.component.ts +export class TlAccordionrComponent implements OnInit { + @Input() private expandOneOnly: boolean; // 不再默认为 false + ... + constructor(private config: TlAccordionrConfigService) { } // 注入 config service + ... + ngOnInit() { + // init expandOneOnly,如果 app.component.html 里没人有设定,用 config service + if (typeof this.expandOneOnly === 'undefined') { + this.expandOneOnly = this.config.expandOneOnly; + } ...}...} + +// app.module.ts +imports: [TlAccordionrModule.forRoot()] +``` +### 添加 Amination +```html + +
+``` + +```ts +// tl-accordionr-panel.component.ts +@Component({..., animations: [trigger('contentState', [...])] }) +export class TlAccordionrPanelComponent {...} +``` +有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 + +### 测试 +- 配置 TestHostComponent: + ```ts + @Component({template: ` + `}) + class TestHostComponent { + panels = [ ... ]; } + ``` +- 测试是否可以按照 TestHostComponent 配置来初始化: + ```ts + it('should initialize with TestHost setup', () => { + expect(accordionComponent['expandOneOnly']).toBe(true); + expect(accordionComponent['panels']).toEqual(componentHost.panels); + expect(accordionComponent['lastExpandedPanel']).toEqual(componentHost.panels[0]); }); + ``` +- 测试点击某个 panel 的 title 之后,是否可以 toggle 这个 panel,并设置其他 panel: + ```ts + it('should act as expected when click on title', () => { + const titleElArr = fixtureHost.debugElement.queryAll(By.css('tl-accordionr .card-header')); + const contentElArr = fixtureHost.debugElement.queryAll(By.css('tl-accordionr .card-block')); + + expect(accordionComponent['panels'][0].expanded).toBe(true); // [0] is expanded initially + titleElArr[1].triggerEventHandler('click', {}); // click on [1] + fixtureHost.detectChanges(); + // ... expect * 20 + }); + ``` +## 总结 +按照 model driven 的思路制作组件,组件内部逻辑清晰,容易写,方便看,测试也简单。 + diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/screen-shot-r.png b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/screen-shot-r.png new file mode 100644 index 0000000000000000000000000000000000000000..894b6875371e940d98b9580524096e4bc23d1414 GIT binary patch literal 9699 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 Fe*qt0+%^CJ literal 0 HcmV?d00001 From 2dbc6c62b8fe638f19206e31143086ec8529531e Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 16:31:43 +0800 Subject: [PATCH 02/20] fixes format --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index dbc48f0..039d26e 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -183,7 +183,9 @@ export class TlAccordionrPanelComponent {...} ``` 有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 + ### 测试 + - 配置 TestHostComponent: ```ts @Component({template: ` @@ -191,6 +193,7 @@ export class TlAccordionrPanelComponent {...} class TestHostComponent { panels = [ ... ]; } ``` + - 测试是否可以按照 TestHostComponent 配置来初始化: ```ts it('should initialize with TestHost setup', () => { @@ -198,6 +201,7 @@ export class TlAccordionrPanelComponent {...} expect(accordionComponent['panels']).toEqual(componentHost.panels); expect(accordionComponent['lastExpandedPanel']).toEqual(componentHost.panels[0]); }); ``` + - 测试点击某个 panel 的 title 之后,是否可以 toggle 这个 panel,并设置其他 panel: ```ts it('should act as expected when click on title', () => { @@ -210,6 +214,8 @@ export class TlAccordionrPanelComponent {...} // ... expect * 20 }); ``` + + ## 总结 按照 model driven 的思路制作组件,组件内部逻辑清晰,容易写,方便看,测试也简单。 From af230aa0a1766b01dc23697f8f90e875885f66e6 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 16:35:49 +0800 Subject: [PATCH 03/20] moves r to the front --- .../articles/timliu/simple-accordion-reactive/_index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 039d26e..e012428 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -6,8 +6,8 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - [template driven form](https://scotch.io/tutorials/using-angular-2s-template-driven-forms),几乎可以把所有的数据和逻辑(比如 validation)都放在 template 里; - [model driven form](https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol)(或者叫 reactive form),template 很简单,数据和逻辑放在 model 里。 -组件的制作也可以参照这两种不同的思路。本篇是一个系列的下集,即按照 model driven 思路,应用 Angular 2 制作一个 Accordionr 组件。而上集应用了 template driven 思路。 - +组件的制作也可以参照这两种不同的思路。本篇是一个系列的下集,即按照 model driven 思路,应用 Angular 2 制作一个 Accordionr 组件。而上集应用了 template driven 思路。 +(Accordion 后面跟一个 r,这个 r 是 reactive 的意思,reactive 是 model driven 的意思,大家别误会。) ## 读者指引 - 笔者的偏见:model driven 大法好。仅与上集比较'代码长度'这一项,大家就可以得出结论了。 @@ -35,7 +35,7 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 ## 小目标 我们希望呈现的效果是: ![页面显示](./screen-shot-r.png) -(这个 R 是 Reactive 的意思,Reactive 是 model driven 的意思,大家别误会。) 初始显示 content0;点击 title1,展开 content1,收起 content0;点击 title2,什么也不做,因为 panel2 是 disabled。 +初始显示 content0;点击 title1,展开 content1,收起 content0;点击 title2,什么也不做,因为 panel2 是 disabled。 这背后是一个 accordionr (最后有个 r) component,另外需要 app.component 提供数据,`Panel` interface 在 accordionr 组件目录里设定。 ```html @@ -201,7 +201,7 @@ export class TlAccordionrPanelComponent {...} expect(accordionComponent['panels']).toEqual(componentHost.panels); expect(accordionComponent['lastExpandedPanel']).toEqual(componentHost.panels[0]); }); ``` - + - 测试点击某个 panel 的 title 之后,是否可以 toggle 这个 panel,并设置其他 panel: ```ts it('should act as expected when click on title', () => { From 2bda5efd46147fd00d1f634cd2fd0e9d33865859 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 19 Dec 2016 16:37:36 +0800 Subject: [PATCH 04/20] fixes format --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index e012428..d9bbdca 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -7,7 +7,8 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - [model driven form](https://scotch.io/tutorials/using-angular-2s-model-driven-forms-with-formgroup-and-formcontrol)(或者叫 reactive form),template 很简单,数据和逻辑放在 model 里。 组件的制作也可以参照这两种不同的思路。本篇是一个系列的下集,即按照 model driven 思路,应用 Angular 2 制作一个 Accordionr 组件。而上集应用了 template driven 思路。 -(Accordion 后面跟一个 r,这个 r 是 reactive 的意思,reactive 是 model driven 的意思,大家别误会。) +(Accordion 后面跟一个 r,这个 r 是 reactive 的意思,reactive 是 model driven 的意思,大家别误会。) + ## 读者指引 - 笔者的偏见:model driven 大法好。仅与上集比较'代码长度'这一项,大家就可以得出结论了。 @@ -15,12 +16,15 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - NG2 - [模板语法](https://angular.cn/docs/ts/latest/guide/template-syntax.html)。 - NG2 - ngFor 的展开写法(模板语法的一小部分)(参见 trotyl 的《[Angular 2 中的 Sturctural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective)》): 一般我们都是写 `
...
`,展开后是 + ```html ``` + 上面的代码会将 `.card` 按 panel 循环。这里只有 `.card` 一个元素。如果我们需要同时循环多于一个元素的时候,`*ngFor` 这样含有星号的写法就行不通了,只能使用展开写法,即 + ```html - ``` + ``` + - NG2 - 大概知道 [Angular Animation](https://angular.cn/docs/ts/latest/guide/animations.html)。 + - NG2 - 大概知道 [Angular Testing](https://angular.cn/docs/ts/latest/guide/testing.html)。 - 文章使用 angular-cli 的 [generate 指令](https://github.com/angular/angular-cli#generating-components-directives-pipes-and-services)(简写为 `ng g`)来生成基础代码。 @@ -229,6 +231,13 @@ export class TlAccordionrPanelComponent {...} // expect * 1000 })); ``` +### 发布到 NPM +tl-accordionr module 写好了,请别人来试试吧。你可以: +- zip 一下发个邮件,然后告诉朋友 upzip 之后怎么怎么样 ... +- 或者发布到 NPM,然后告诉朋友 `npm i tl-accordionr` ... + +后续文章会简单介绍如何将使用 angular-cli 做好的 module 发布到 NPM 上。 + ## 总结 按照 model driven 的思路制作组件,组件内部逻辑清晰,容易写,方便看,测试也简单。 From f634f5bcf3777183082ec74770c0c8002a09a40c Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Tue, 20 Dec 2016 13:43:28 +0800 Subject: [PATCH 10/20] minor fix --- .../articles/timliu/simple-accordion-reactive/_index.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index cba6ec8..7f30ad1 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -166,7 +166,7 @@ export class TlAccordionrComponent implements OnInit { constructor(private config: TlAccordionrConfigService) { } // 注入 config service ... ngOnInit() { - // init expandOneOnly,如果 app.component.html 里没人有设定,用 config service + // init expandOneOnly,如果 app.component.html 里没有设定,用 config service if (typeof this.expandOneOnly === 'undefined') { this.expandOneOnly = this.config.expandOneOnly; } ...}...} @@ -185,9 +185,11 @@ imports: [TlAccordionrModule.forRoot()] ```ts // tl-accordionr-panel.component.ts @Component({..., animations: [trigger('contentState', [...])] }) -export class TlAccordionrPanelComponent {...} +export class TlAccordionrPanelComponent { + @Input() private animation: boolean = false; +} ``` -有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 +有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。另外,可以给 accordionr component 添加一个 `@Input() animation: boolean` 开关(config.service 里也要添加),用户可以控制是否显示动画。 ### 测试 From 5601e578ba3fa3df1a92c8dd1980012e26346d99 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Tue, 20 Dec 2016 13:50:59 +0800 Subject: [PATCH 11/20] minor fix --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 7f30ad1..c5ec4ae 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -10,11 +10,11 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 (Accordion 后面跟一个 r,这个 r 是 reactive 的意思,reactive 是 model driven 的意思,大家别误会。) ## 读者指引 -- 笔者的偏见:model driven 大法好。仅与上集比较'代码长度'这一项,大家就可以得出结论了。 +- 笔者的偏见:model driven 大法好。大家可以对比上集的代码长度和知识点列表长度,就很容易得出结论了。 - 本文涉及到的知识点: - NG2 - 了解 [模板语法](https://angular.cn/docs/ts/latest/guide/template-syntax.html)。 - - NG2 - ngFor 的展开写法(模板语法的一小部分)(参见 trotyl 的《[Angular 2 中的 Sturctural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective)》): + - NG2 - 了解 ngFor 的展开写法(模板语法的一小部分)(参见 trotyl 的《[Angular 2 中的 Sturctural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective)》): 一般我们都是写 `
...
`,展开后是 ```html From e199b89224dd8af33e9335cc673eaf7b0fdffb3f Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Tue, 20 Dec 2016 14:09:08 +0800 Subject: [PATCH 12/20] =?UTF-8?q?refactors=20=E5=AE=9E=E7=8E=B0=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E9=85=8D=E7=BD=AE=20app=20=E5=86=85=E6=89=80=E6=9C=89?= =?UTF-8?q?=20accordionr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simple-accordion-reactive/_index.md | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index c5ec4ae..1904769 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -146,20 +146,26 @@ export class TlAccordionrComponent implements OnInit { ``` ### 实现全局配置 app 内所有 accordionr +- 需求六:我们需要一个 config service。 +- 需求七:将 config service 添加到 accordionr module 的 providers 列表里。 +- 需求八:在 accordionr component 里注入这个 config service。 +- 需求九:可以在 app.module 里替换这个 config service。 +- 需求十:可以不提供 config service。 + ```ts -// tl-accordionr-config.service.ts +// tl-accordionr-config.service.ts 需求六 @Injectable() export class TlAccordionrConfigService { expandOneOnly = false; } -// tl-accordionr.module.ts +// tl-accordionr.module.ts 需求七 export class TlAccordionrModule { - static forRoot(): ModuleWithProviders { + static withProviders(): ModuleWithProviders { return { ngModule: TlAccordionrModule, providers: [TlAccordionrConfigService] }}} -// tl-accordionr.component.ts +// tl-accordionr.component.ts 需求八 export class TlAccordionrComponent implements OnInit { @Input() private expandOneOnly: boolean; // 不再默认为 false ... @@ -171,9 +177,16 @@ export class TlAccordionrComponent implements OnInit { this.expandOneOnly = this.config.expandOneOnly; } ...}...} -// app.module.ts -imports: [TlAccordionrModule.forRoot()] +// app.module.ts 使用默认 config service +imports: [TlAccordionrModule.withProviders()] + +// app.module.ts 替换默认 config service 需求九 +imports: [TlAccordionrModule.withProviders()] +providers: [{provide: TlAccordionrConfigService, useValue: TlAccordionrConfigServiceAlternative}] + +// 需求十,大家试试看(提示: 在 accordionr component 的 constructor 里使用 @Optional() ...) ``` +如果要 ### 添加 Amination ```html From 490c02ff5c71bc903b1fd6dc6589c5cfff8b3cc2 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Tue, 20 Dec 2016 14:11:31 +0800 Subject: [PATCH 13/20] minor fix --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 1904769..a4babff 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -186,7 +186,7 @@ providers: [{provide: TlAccordionrConfigService, useValue: TlAccordionrConfigSer // 需求十,大家试试看(提示: 在 accordionr component 的 constructor 里使用 @Optional() ...) ``` -如果要 + ### 添加 Amination ```html From 455722edf4ee2a24bcd924d41c941195f317e3cf Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Wed, 21 Dec 2016 12:42:27 +0800 Subject: [PATCH 14/20] adds bootstrap.scss --- .../articles/timliu/simple-accordion-reactive/_index.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index a4babff..544a94f 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -70,6 +70,8 @@ export class AppComponent { ### 脚手架搭建(生成基础代码) 我们需要的组成部分包括:accordionr component、config service,还有一个 interface 文件。 ``` +> ng new my-awesomer-package --style=scss +> cd my-awesomer-package > ng g module tl-accordionr ... (生成 TlAccordionrModule 以及 TlAccordionrComponent) > ng g service tl-accordionr/tl-accordionr-config @@ -78,6 +80,11 @@ export class AppComponent { 然后在 TlAccordionrModule 里,加上 `exports: [TlAccordionrComponent]`,在 app.module 里加上 `imports: [TlAccordionrModule]`,就可以开始在 app.component.html 里面使用 tl-accordionr 标签了。 生成 TlAccordionrModule 这个 ngModule 的目的是:预留 provider 位置,方便以后配置全局变量,比如要求 app 里所有的 accordionr 都是怎么怎么样的。 +### 引入 bootstrap.scss +本文参考 ng-bootstrap,使用 bootstrap 4 的样式。 +- 敲指令:`npm install bootstrap@4.0.0-alpha.5 -S`; +- 在 `my-awesome-package\src\styles.scss` 中添加 `@import '~bootstrap/scss/bootstrap.scss';`。 + ### 实现 accordionr 组件显示 panels ```ts // tl-accordionr.component.ts From c3bc30a9bbefbdf63d5f77200e5a4f3db814f191 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Wed, 21 Dec 2016 16:39:01 +0800 Subject: [PATCH 15/20] switches to ng-container, reminded by trotyl --- .../simple-accordion-reactive/_index.md | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 544a94f..48915c0 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -14,23 +14,15 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - 本文涉及到的知识点: - NG2 - 了解 [模板语法](https://angular.cn/docs/ts/latest/guide/template-syntax.html)。 - - NG2 - 了解 ngFor 的展开写法(模板语法的一小部分)(参见 trotyl 的《[Angular 2 中的 Sturctural Directive](https://wx.angular.cn/library/article/Angular2%E4%B8%AD%E7%9A%84StructuralDirective)》): - 一般我们都是写 `
...
`,展开后是 - - ```html - - ``` - - 上面的代码会将 `.card` 按 panel 循环。这里只有 `.card` 一个元素。如果我们需要同时循环多于一个元素的时候,`*ngFor` 这样含有星号的写法就行不通了,只能使用展开写法,即 + - NG2 - 了解 [``](https://github.com/angular/angular/pull/9197):在使用 ngFor 的时候一般我们都是写 `
...
`,`.card-header` 元素会按 panel 循环。这里只有 `.card-header` 一个元素。如果还有一个姊妹元素 `.card-block`,我们希望 `.card-header` 和 `.card-block` 一起循环,又不想额外添加 `
`,该怎么办呢?可以这样: ```html - + ``` + (写作本文之前,我还不知道有个 ``,多亏 trotyl 提醒。这里对 trotyl 表示感谢。) - NG2 - 大概知道 [Angular Animation](https://angular.cn/docs/ts/latest/guide/animations.html)。 - NG2 - 大概知道 [Angular Testing](https://angular.cn/docs/ts/latest/guide/testing.html)。 @@ -95,10 +87,10 @@ export class TlAccordionrComponent { ```html
- +
``` (role 和 class 配合 bootstrap 使用)这样,在 app.component.ts 里定义的 panels 就都显示出来了,一视同仁,不论 expanded、disabled。 From 81bbb32d70aaf7d4e6d9f126027e59eba9979194 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Wed, 21 Dec 2016 16:43:00 +0800 Subject: [PATCH 16/20] minor fix --- .../simple-accordion-reactive/_index.md | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 48915c0..766e0f7 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -14,15 +14,19 @@ Angular 的文档翻了一遍又一遍,还是记不住,边用边学效果会 - 本文涉及到的知识点: - NG2 - 了解 [模板语法](https://angular.cn/docs/ts/latest/guide/template-syntax.html)。 - - NG2 - 了解 [``](https://github.com/angular/angular/pull/9197):在使用 ngFor 的时候一般我们都是写 `
...
`,`.card-header` 元素会按 panel 循环。这里只有 `.card-header` 一个元素。如果还有一个姊妹元素 `.card-block`,我们希望 `.card-header` 和 `.card-block` 一起循环,又不想额外添加 `
`,该怎么办呢?可以这样: + - NG2 - 了解 [``](https://github.com/angular/angular/pull/9197):在使用 ngFor 的时候一般我们都是写: + ```html +
...
+ ``` + `.card-header` 元素会按 panel 循环。这里只有 `.card-header` 一个元素。如果还有一个姊妹元素 `.card-block`,我们希望 `.card-header` 和 `.card-block` 一起循环,又不想额外添加 `
`,该怎么办呢?可以这样: - ```html - -
...
-
...
-
- ``` - (写作本文之前,我还不知道有个 ``,多亏 trotyl 提醒。这里对 trotyl 表示感谢。) + ```html + +
...
+
...
+
+ ``` + 这个 `` 是不会被 render 出来的。(写作本文之前,我还不知道有个 ``,多亏 trotyl 提醒。这里对 trotyl 表示感谢。) - NG2 - 大概知道 [Angular Animation](https://angular.cn/docs/ts/latest/guide/animations.html)。 - NG2 - 大概知道 [Angular Testing](https://angular.cn/docs/ts/latest/guide/testing.html)。 From a67a1e9d353d39179a15f27609d8d1406c68d950 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Fri, 23 Dec 2016 10:14:40 +0800 Subject: [PATCH 17/20] minor fixes --- .../timliu/simple-accordion-reactive/_index.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 766e0f7..2bb6226 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -201,11 +201,9 @@ providers: [{provide: TlAccordionrConfigService, useValue: TlAccordionrConfigSer ```ts // tl-accordionr-panel.component.ts @Component({..., animations: [trigger('contentState', [...])] }) -export class TlAccordionrPanelComponent { - @Input() private animation: boolean = false; -} +export class TlAccordionrPanelComponent {} ``` -有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。另外,可以给 accordionr component 添加一个 `@Input() animation: boolean` 开关(config.service 里也要添加),用户可以控制是否显示动画。 +有需要的同学可以参考 [angular.cn 里 animation 的文档](https://angular.cn/docs/ts/latest/guide/animations.html)来实现动画效果。 ### 测试 @@ -246,10 +244,13 @@ export class TlAccordionrPanelComponent { fixtureHost.detectChanges(); ... tick(500); // 假设我们的 animation 0.5 秒演完,假装我们等他 0.5 秒 - // expect * 1000 })); + // expect * 1000 + })); ``` + ### 发布到 NPM + tl-accordionr module 写好了,请别人来试试吧。你可以: - zip 一下发个邮件,然后告诉朋友 upzip 之后怎么怎么样 ... - 或者发布到 NPM,然后告诉朋友 `npm i tl-accordionr` ... From 66b1eba76eeb5b107a922be75beb9c171ff45be5 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sat, 24 Dec 2016 23:19:46 +0800 Subject: [PATCH 18/20] adds hint for future article --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 2bb6226..5cc2314 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -260,3 +260,6 @@ tl-accordionr module 写好了,请别人来试试吧。你可以: ## 总结 按照 model driven 的思路制作组件,组件内部逻辑清晰,容易写,方便看,测试也简单。 +## 后续文章 +下一个 component 是 modal。在 `app.component.html` 里这样用 `` ... + From 3818dd508c230edfc1100b41c9055264d43c0032 Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Sat, 24 Dec 2016 23:26:52 +0800 Subject: [PATCH 19/20] minor fix --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index 5cc2314..a6c9a62 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -255,11 +255,9 @@ tl-accordionr module 写好了,请别人来试试吧。你可以: - zip 一下发个邮件,然后告诉朋友 upzip 之后怎么怎么样 ... - 或者发布到 NPM,然后告诉朋友 `npm i tl-accordionr` ... -后续文章会简单介绍如何将使用 angular-cli 做好的 module 发布到 NPM 上。 - ## 总结 按照 model driven 的思路制作组件,组件内部逻辑清晰,容易写,方便看,测试也简单。 ## 后续文章 -下一个 component 是 modal。在 `app.component.html` 里这样用 `` ... - +- 下一个 component 是 modal,当然,也是 model driven。在 `app.component.html` 里这样用 `` ... +- 另外,后续也会有文章介绍如何将使用 angular-cli 做好的 module 发布到 NPM 上 ... From 5b3e77ec55d74009f5f0c44318fb3812b577442f Mon Sep 17 00:00:00 2001 From: Liu Tim Date: Mon, 26 Dec 2016 01:17:36 +0800 Subject: [PATCH 20/20] adds reminder that component optional when generating module --- .../api/articles/timliu/simple-accordion-reactive/_index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md index a6c9a62..55ac5ce 100644 --- a/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md +++ b/src/app/_shared/api/articles/timliu/simple-accordion-reactive/_index.md @@ -68,13 +68,14 @@ export class AppComponent { ``` > ng new my-awesomer-package --style=scss > cd my-awesomer-package -> ng g module tl-accordionr +> ng g module tl-accordionr --routing // 注1 ... (生成 TlAccordionrModule 以及 TlAccordionrComponent) > ng g service tl-accordionr/tl-accordionr-config > (假设当前目录为 app)touch tl-accordionr/tl-accordionr.interface.ts ``` 然后在 TlAccordionrModule 里,加上 `exports: [TlAccordionrComponent]`,在 app.module 里加上 `imports: [TlAccordionrModule]`,就可以开始在 app.component.html 里面使用 tl-accordionr 标签了。 -生成 TlAccordionrModule 这个 ngModule 的目的是:预留 provider 位置,方便以后配置全局变量,比如要求 app 里所有的 accordionr 都是怎么怎么样的。 +生成 TlAccordionrModule 这个 ngModule 的目的是:预留 provider 位置,方便以后配置全局变量,比如要求 app 里所有的 accordionr 都是怎么怎么样的。 +(注1:从Angular-CLI 1.0.0-beta.23 (2016-12-15) 开始,`ng g module` 不再自动生成同名 component,可以手动生成,或添加 `--routing` flag。参考[链接](https://github.com/angular/angular-cli/commit/2fb2d13)。) ### 引入 bootstrap.scss 本文参考 ng-bootstrap,使用 bootstrap 4 的样式。