从这里开始我们来讲语法

NgModule简介

declarations 数组 的规则

该模块想要正常工作,可能会依赖一些组件、指令和管道,那就必须将它们声明到declarations中,不过引入也有一些规则,以组件为例:

  • 模块中不能使用未声明过(没有添加到declarations中)的组件
  • 一个组件只能被一个模块声明
  • 在declarations中的组件默认只能在当前模块中使用,要想让其他模块使用,必须exports出去(参考下文的exports)

以上规则同样适用于指令和管道

imports 数组规则

imports数组只会出现在@NgModule装饰器中,一个模块想要正常工作,除了本身的依赖项(declarations),还可能需要其他模块导出的依赖项。
只要是angular module,都可以导入imports数组中,比如自定义的模块,第三方或者ng内置的都可以

bootstrap 数组规则

应用是通过引导根模块 AppModule 来启动的,引导过程还会创建 bootstrap 数组中列出的组件,并把它们逐个插入到浏览器的 DOM 中。
该数组中的每个组件,都作为组件树的根(根组件),后续所有组件都是基于根组件的(如图)。
虽然也可以在宿主页面中放多个组件,但是大多数应用只有一个组件树,并且只从一个根组件开始引导。
这个根组件通常叫做 AppComponent,并且位于根模块的 bootstrap 数组中。
image.png

  1. # app.module.ts
  2. import { BrowserModule } from '@angular/platform-browser';
  3. import { NgModule } from '@angular/core';
  4. import { AppRoutingModule } from './app-routing.module';
  5. import { AppComponent } from './app.component';
  6. // 这是一个NgModule
  7. // angular module就是一个普通的类,但是这个类,一旦被@NgModule所装饰
  8. ,那这个类就可以被称为angular module
  9. @NgModule({
  10. declarations: [
  11. AppComponent // 该模块的依赖项 需要显示的声明
  12. ],
  13. imports: [
  14. BrowserModule, //导入其他的ngModule
  15. AppRoutingModule
  16. ],
  17. providers: [], // 这个是 给外界提供的 服务 service 提供各种服务。
  18. bootstrap: [AppComponent] // 这个属性一般只有根组件用到,在main中使用了它
  19. 根组件,Angular 创建它并插入 index.html 宿主页面
  20. })
  21. export class AppModule { }
  22. # main.ts
  23. import { enableProdMode } from '@angular/core';
  24. import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
  25. import { AppModule } from './app/app.module';
  26. import { environment } from './environments/environment';
  27. import 'bootstrap';
  28. if (environment.production) {
  29. enableProdMode();
  30. }
  31. platformBrowserDynamic().bootstrapModule(AppModule)
  32. .catch(err => console.error(err));

那么我们如何创建一个Moduel? 使用cli就可以了 CLI地址

  1. ng g module my-module
  2. # 如果你这样写 就会生成子文件
  3. ng g module my-module/chile-module

生成之后的样子
image.png

  1. import { NgModule } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. @NgModule({
  4. declarations: [],
  5. imports: [
  6. CommonModule
  7. ]
  8. })
  9. export class MyModuleModule { }

基础的展示数据

显示数据

ng的模版中,默认用双大括号{{}}绑定组件中的变量显示出来

  1. import { Component } from '@angular/core';
  2. // @Component({
  3. // selector: 'app-root', // 选择器和dom的选择器保持一致的语法
  4. // template: `
  5. // <h1>{{title}}</h1>
  6. // <h2>My favorite hero is: {{myHero}}</h2>
  7. // `,
  8. // styles: [`h1 { color: red }`]
  9. // })
  10. // @Component({
  11. // selector: 'app-root',
  12. // templateUrl: './app.component.html',
  13. // styleUrls: ['./app.component.scss']
  14. // })
  15. export class AppComponent {
  16. title = 'myapp';
  17. }

模版表达式

  1. import { Component } from '@angular/core';
  2. // @Component({
  3. // selector: 'app-root',
  4. // templateUrl: './app.component.html',
  5. // styleUrls: ['./app.component.scss']
  6. // })
  7. @Component({
  8. selector: 'app-root', // 选择器和dom的选择器保持一致的语法
  9. template: `
  10. <h1>{{title}}</h1>
  11. <h2>My favorite hero is: {{myHero}}</h2>
  12. <br/>
  13. <h2>Fn:{{ getValue() }}</h2>
  14. <br />
  15. <p>与方法结合 {{ price * 0.7 + getValue() }}.</p>
  16. `,
  17. styles: [`h1 { color: red }`]
  18. })
  19. export class AppComponent {
  20. // 绑定变量
  21. title = 'myapp';
  22. myHero = '666';
  23. price = 23;
  24. // 绑定方法
  25. getValue = () => {
  26. return "XXX"
  27. }
  28. // 注意: 使用模板表达的时候一定要注意 不能有副作用的变量!
  29. }

绑定属性

主要用来绑定html中的属性 比如img 的src a标签的href等…

  1. import { Component } from '@angular/core';
  2. @Component({
  3. selector: 'app-root',
  4. template: `
  5. <div>
  6. // 一般的属性
  7. <br/>
  8. <img src="../assets/01.png" alt="madao" />
  9. <img [src]="imgValue" alt="madao" />
  10. <img bind-src="imgValue" alt="madao" />
  11. <br>
  12. <table class="table-bordered">
  13. <tr>
  14. <th>name</th>
  15. <th>phone</th>
  16. <th>age</th>
  17. </tr>
  18. <tr>
  19. <td>张三</td>
  20. <td>13398490594</td>
  21. <td>33</td>
  22. </tr>
  23. <tr>
  24. <td [colSpan]="colSpan">李四</td>
  25. <td>15079049984</td>
  26. <td>22</td>
  27. </tr>
  28. </table>
  29. <button class="btn btn-primary" [disabled]="isDisabled">click</button>
  30. </div>
  31. // 自定义的属性 规范:虽然{{ 2 }}也能给属性绑定值 但是还是建议 写 [ ]
  32. <br />
  33. <span [attr.data-title]="customTitle">一行文字</span>
  34. <span [attr.title]="customTitle">test title</span>
  35. <span [title]="customTitle">test title</span>
  36. `,
  37. styles:[
  38. ` img { width:200px; } `
  39. ]
  40. })
  41. export class AppComponent {
  42. imgValue = '../assets/01.png';
  43. user = {
  44. name: 'madao',
  45. pic: this.imgValue
  46. };
  47. colSpan = 2;
  48. isDisabled = false;
  49. customTitle = '还是老李NB';
  50. }

绑定样式

实际上绑定样式也是非常的简单 需要注意的一点就是其的 优先级的问题 总结下来就是两点

  • 某个类或样式绑定越具体,它的优先级就越高
  • 绑定总是优先于静态属性 ```typescript import { Component } from ‘@angular/core’;

// @Component({ // selector: ‘app-root’, // templateUrl: ‘./app.component.html’, // styleUrls: [‘./app.component.scss’] // })

@Component({ selector: ‘app-root’, // 选择器和dom的选择器保持一致的语法 template: // 绑定class当个的 <hr /> <button type="button" class="btn" [class.btn-primary]="theme === 'primary'">Primary</button> <button type="button" class="btn" [class.btn-secondary]="true">secondary</button> <button type="button" class="btn" [class.btn-success]="isSuccess">success</button> <button type="button" class="btn" [class.btn-danger]="'啦啦啦'">danger</button> <button type="button" class="btn" [class.btn-danger]="0">danger</button> <button type="button" class="btn" [class.btn-danger]="undefined">danger</button> // 绑定class多个的 <hr /> <!-- 也可以用内置指令ngClass [ngClass]="btnCls" 等价于 class.btnCls --> <button type="button" [ngClass]="btnCls">btnCls</button> <button type="button" [ngClass]="btnCls2">btnCls2</button> <button type="button" [ngClass]="btnCls3">btnCls3</button> <br /> // 绑定Style <hr /> <!-- 及其不推荐的写法!单个 style --> <p [style.height]="'50px'" [style.border]="'1px solid'">设置高度</p> <!-- 多个!style --> <p [ngStyle]="style3">style3</p>, styles:[ img { width:200px; } ] }) export class AppComponent { theme = ‘primary’; isSuccess = true;

  1. btnCls = 'btn btn-primary';
  2. btnCls2 = ['btn', 'btn-success'];
  3. btnCls3 = {
  4. btn: true,
  5. 'btn-info': true
  6. };
  7. style3 = {
  8. width: '200px',
  9. height: '50px',
  10. 'text-align': 'center',
  11. border: '1px solid'
  12. }

}

  1. <a name="cnUd5"></a>
  2. ## 创建组件
  3. > 上面的东西我们观察了一下发现 实际上都放在了 app.component.ts 这一个组件中,那么我们如何自己创建自己的组件呢? [CLI文档](https://angular.cn/cli/generate#component)
  4. ```shell
  5. # 下面的cli命令就能执行做到这件事
  6. ng g c comp1 (在src/app下创建名为comp1的组件)
  7. ng g c components/comp1 (在src/app/components下创建名为comp1的组件)
  8. # 生成之后会自动的在你的app.module中的import 中加入它 如果没有你需要加 要不然你的app.componet
  9. 组件中 你就无法使用它

同样的 我们也有些指定的options ,具体在CLI文档中对这个 命令 有详细的描述

  1. ng g c component1 --inline-style --inline-template --skip-tests

这条命令 之后 生成了一个组件 你需要这样去使用它

  1. # app-component1 文件夹中,默认的 创建出来的组件 的 selector 都是以app- 开头 如何去修改
  2. 它呢?
  3. # tslint.js
  4. ++++
  5. "directive-selector": [
  6. true,
  7. "attribute",
  8. "app", // 这个东西就是咯
  9. "camelCase"
  10. ],
  11. ++++
  12. # component1.component.ts
  13. import { Component, OnInit } from '@angular/core';
  14. @Component({
  15. selector: 'app-component1',
  16. template: `
  17. <p>
  18. component1 works!
  19. </p>
  20. `,
  21. styles: [
  22. ]
  23. })
  24. export class Component1Component implements OnInit {
  25. constructor() { }
  26. ngOnInit(): void {
  27. }
  28. }
  29. # 在我们原来的app.components.ts中使用它
  30. import { Component } from '@angular/core';
  31. @Component({
  32. selector: 'app-root', // 选择器和dom的选择器保持一致的语法
  33. template: `
  34. <app-component1 > </app-component1>
  35. `,
  36. styles:[
  37. ` img { width:200px; } `
  38. ]
  39. })
  40. export class AppComponent {
  41. }

绑定事件

对于绑定事件来说也是非常的简单的

  1. import { Component } from '@angular/core';
  2. @Component({
  3. selector: 'app-root',
  4. template: `
  5. <div *ngFor="let item of list">
  6. <button
  7. type="button"
  8. class="btn btn-primary"
  9. (click)="onClick($event, item )">{{ item.name }}</button>
  10. </div>
  11. `,
  12. styleUrls: ['./app.component.scss']
  13. })
  14. export class AppComponent {
  15. list = [ {
  16. name:'老李',
  17. }, {
  18. name: '老王'
  19. }, ];
  20. onClick = ( e:MouseEvent, value ) => {
  21. console.log('value1', event.target);
  22. console.log(' value2', value);
  23. };
  24. }

这里用到了一个循环渲染列表的模板语法 我们暂时不用过多了解你只需要知道是怎么用的就完了

组件间的通信

我们一般在vue 和react 中都叫做什么 props 和 回调 但是在ng中换了个名字 叫做:“输入/输出 属性” 具体的语法如下

首先,我们为了演示这个语法 需要坐下面的工作, 先创建组件
image.png
然后我们先看父子

  1. # father
  2. import { Component, OnInit } from '@angular/core';
  3. @Component({
  4. selector: 'app-father',
  5. template: `
  6. <!--正常的使用
  7. <app-son
  8. [item]=[item]
  9. (newItemEvent)="addItem($event)"
  10. ></app-son>-->
  11. <div>
  12. <!--别名-->
  13. <app-son
  14. [aliasItem]=[item]
  15. (newItem)="addItem($event)"
  16. ></app-son>
  17. </div>
  18. `,
  19. styles: [
  20. ]
  21. })
  22. export class FatherComponent implements OnInit {
  23. item = '2'
  24. addItem(newItem: string) {
  25. console.log('你来啦', newItem);
  26. }
  27. constructor() {}
  28. ngOnInit(): void {
  29. }
  30. }
  31. # son
  32. import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
  33. @Component({
  34. selector: 'app-son',
  35. template: `
  36. <div>
  37. Today's item: {{item}}
  38. <hr />
  39. // 给父组件发射值
  40. <br />
  41. <label>Add an item: <input #newItem></label>
  42. <button (click)="addNewItem(newItem.value)">Add to parent's list</button>
  43. </div>
  44. `,
  45. styles: [
  46. ]
  47. })
  48. export class SonComponent implements OnInit {
  49. // @Input() item: string; // 接受属性 就想在vue中需要给props做点声明一样
  50. // @Output() newItemEvent = new EventEmitter<string>(); // 给父组件的回调
  51. // 如果你需要使用别名就这样就好了
  52. @Input('aliasItem') item: string; // 接受属性 就想在vue中需要给props做点声明一样
  53. @Output('newItem') newItemEvent = new EventEmitter<string>(); // 给父组件的回调
  54. addNewItem(value: string) {
  55. this.newItemEvent.emit(value);
  56. }
  57. constructor() {}
  58. ngOnInit(): void {
  59. console.log(this.item);
  60. }
  61. }

然后再回过头 想一下 不相干的组件怎么办? 实际上依然可以 采取 :“状态提升”的逻辑来搞事情,但是对于NG来说 通信有好多好多的方式 状态提升 可以作为一种,但绝不是 最好的方式在ng中