了解AngularJS的组件教程

77 阅读9分钟

在之前的教程中,我们对Angular JS进行了很好的介绍,甚至使用Angular命令行界面来启动和运行一个项目。在本教程中,我们将更仔细地研究Angular应用程序的代码执行以及构成Angular组件的文件。首先,我们将把Bootstrap作为一个依赖项添加到我们的项目中,这样我们就可以马上得到一些快速和简单的造型。在我们的Angular项目根部的命令行,我们可以输入以下内容。

hello-angular $npm install --save bootstrap

这个加载到项目中,现在它是一个在 **package.json**中的一个依赖项,我们可以在这里看到。

{
  "name": "hello-angular",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~7.0.0",
    "@angular/common": "~7.0.0",
    "@angular/compiler": "~7.0.0",
    "@angular/core": "~7.0.0",
    "@angular/forms": "~7.0.0",
    "@angular/http": "~7.0.0",
    "@angular/platform-browser": "~7.0.0",
    "@angular/platform-browser-dynamic": "~7.0.0",
    "@angular/router": "~7.0.0",
    "bootstrap": "^4.1.3",
    "core-js": "^2.5.4",
    "rxjs": "~6.3.3",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.10.0",
    "@angular/cli": "~7.0.4",
    "@angular/compiler-cli": "~7.0.0",
    "@angular/language-service": "~7.0.0",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.1.1"
  }
}

配置angular.json以使用Bootstrap

通过添加Bootstrap作为一个依赖项,我们现在可以实际配置Angular来使用这些文件。要做到这一点,我们打开 angular.json文件,在 "样式 "部分添加我们想使用的bootstrap css文件的路径。

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "hello-angular": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/hello-angular",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "hello-angular:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "hello-angular:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "hello-angular:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "src/karma.conf.js",
            "styles": [
              "src/styles.css"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "hello-angular-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "prefix": "",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "hello-angular:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "hello-angular:serve:production"
            }
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "hello-angular"
}

Angular组件构建块

一个Angular组件开始是在Typescript中创建的一个类。它有代表可以在视图或模板中使用的数据的属性。它也可以有方法来计算任何需要的商业逻辑。模板是组件的用户界面部分,它是用html编写的,决定了页面上看到的内容。
Angular Component Building Blocks


测试app.component.html中的一些标记

让我们看看Bootstrap样式是否在我们的Angular应用程序中生效了。为此,让我们打开app.component.html文件,添加一些简单的Bootstrap标记,这些标记是我们在Bootstrap网站的例子中发现的。

<div class="jumbotron">
  <div class="container">
    <h1 class="display-3">Hello, world!</h1>
    <p>This is a template for a simple marketing or informational website. It includes a large callout called a
      jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
    <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>
  </div>
</div>

现在,让我们用以下命令来启动我们的Angular应用程序 ng serve命令启动我们的Angular应用程序。
ng-serve with bootstrap

当我们在浏览器中访问http://localhost:4200/,风格设计确实已经生效了
angular application with bootstrap installed


AngularJS中的index.html

在AngularJS中,当应用程序运行时,会提供index.html文件。在我们的单页应用程序中,这就是被提供的单页。你会注意到,我们实际上把上面的html代码放在一个名为app.component.html的文件中。那么,当我们在浏览器中加载index.html页面时,这些HTML代码是如何显示的呢?Angular CLI创建了****作为应用程序的根组件。正是这个组件将整个Angular应用程序联系起来。我们可以在这里看到index.html中的这个标记。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>HelloAngular</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

一个组件有几个文件

在Angular中,每个组件都有几个与它相关的文件。在src/app目录下,我们可以看到命令行界面为我们创建的所有文件,以构建主****组件。
the files that make up an angular component


检查app.component.ts

Angular看的第一件事是app.component.ts文件中的选择器属性。注意,这里是一个字符串值 "app-root"。因此,当Angular加载这个组件时,它会寻找一个与'app-root'字符串相匹配的标签,然后用这个渲染的组件替换该标签。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
}

检查main.ts

如果index.html文件是Angular应用程序的主要占位符,那么main.ts文件就是Angular脚本引擎启动的地方。

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

app module angular

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

根据上述文件,对Angular如何启动的快速总结如下。

  • Angular从main.ts开始
  • 使用app.module.ts作为参数来启动应用程序
  • 这个模块指定在启动时寻找AppComponent
  • 然后Angular查看该组件并找到app-root选择器
  • 最后,当index.html加载时,<app-root></app-root>被替换成渲染的组件。

组件

组件是Angular的一个关键功能。每个组件都有自己的模板、自己的HTML标记、自己的样式以及自己的业务逻辑。VueJS用一种很好的方式将所有这些功能包装成所谓的单文件组件。在Angular中,我们把这些职责放在不同的文件中。组件允许开发者将复杂的网页分割成可重用的部分。通过这种方法,你可以一次性创建业务逻辑,然后随心所欲地使用它。


创建你自己的组件

为了更好地理解Angular组件的文件结构,我们现在可以去创建一个。现在,我们已经介绍过的应用程序组件是有点特别的。它是整个单页应用程序的根元素,因此在index.html文件中有一个选择器。我们创建的新组件在index.html文件中不会有自己的选择器,但会被添加到app.component.html文件中。


在/app下添加一个子文件夹

为了开始构建一个新的Angular组件,我们将在/app文件夹下添加一个新的文件夹来存放与新组件相关的任何文件。我们可以想象我们正在监控网络上的一些虚拟机。所以我们将创建一个虚拟机组件。这意味着我们需要一个虚拟机文件夹来存放我们的组件文件。
folder to hold angular component files


创建组件的typescript文件

创建了我们的文件夹后,我们现在可以添加一个名为virtual-machine.component.ts的文件。
angular component naming convention


创建组件模板文件

除了我们刚刚创建的Typescript文件外,我们还需要创建相关的模板文件。这通常会是相同的命名方式,但有一个html后缀。所以我们也可以在同一个文件夹中创建virtual-machine.component.html文件。


为你的组件定义TypeScript类

现在可以开始构建组件了,但我们从哪里开始呢?在Angular中,你可以把组件看作是面向对象编程中的类。在Angular中,它是一个Typescript类,然后Angular会根据需要将其实例化。我们可以在virtual-machine.component.ts文件中放置以下代码。

import { Component } from "@angular/core";

@Component({
    selector: 'app-virtual-machine',
    templateUrl: './virtual-machine.component.html'
})
export class VirtualMachineComponent {}

在上面的片段中,我们现在已经创建了VirtualMachineComponent类,它被导出了,所以可以在其他地方使用。注意该类的命名规则。它是组件本身的名字,后面是Component这个词。现在,Angular知道这是一个组件的方式是通过使用@Component装饰器。这个装饰器接受一个对象,其中的键/值对是这个组件的配置选项。注意这个 **selector属性被设置为 "app-virtual-machine"。这就是我们如何识别和使用这个组件。换句话说,我们现在可以在模板文件中使用**引用这个组件。该 **templateUrl**属性被用来指向包含该组件标记的html文件。首先,我们可以在我们的模板文件中为这个组件设置这个简单的标记。

virtual-machine.component.html

<h1>The Virtual Machine Component</h1>

同时注意virtual-machine.component.ts文件顶部的导入语句。组件装饰器不是TypeScript自动知道的东西。当添加导入语句时,我们把我们想要导入的东西的名字放在大括号**{ }**之间。我们想要访问组件装饰器,这就是为什么我们看到 { Component }.它被从angular核心包中导入。有了这个,@Component装饰器对typescript是可用的,所以当文件被编译为JavaScript时,它可以正确地进行编译。

  • Angular组件类的关键点

  • 选择一个好的名字。它既是类的名称,也是组件的名称。

  • 使用PascalCasing。这意味着名字中的每一个字都是大写的。

  • YourCoolComponent。在类名后面加上 "组件 "是很常见的。

  • export关键字

  • export关键字使得该类可以在应用程序的其他地方被导入。

  • 数据被存储在类的属性中

  • 使用正确的数据类型。

  • 如果需要的话,设置一个默认值。

  • 遵循camelCase惯例。

  • 逻辑在方法中

  • 在用于添加逻辑或执行组件操作的方法上使用camelCase。


注册我们的新组件!

你可能很想立即投入使用你的新组件在你这样做之前,你需要告诉Angular这个新的组件,并且它已经可以使用了。要做到这一点,必须在app.module.ts文件中注册该组件。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { VirtualMachineComponent } from './virtual-machine/virtual-machine.component';

@NgModule({
  declarations: [
    AppComponent,
    VirtualMachineComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

上面强调的对app.module.ts文件的补充将向Angular注册我们的新组件。我们可以看到,在声明数组中,已经有一个AppComponent被注册。要添加我们的新组件,我们只需添加一个逗号,然后添加我们的组件的名称,即VirtualMachineComponent。除了在声明数组中加入我们的组件名称外,我们还需要导入这个组件,正如我们在高亮行中看到的那样。


尝试新的组件

我们知道,任何新的组件都不能直接在Angular应用程序的index.html文件中使用。然而,我们可以在已经存在的AppComponent中使用它们。让我们打开app.component.html文件,为我们新创建的组件添加一个引用。

<div class="jumbotron">
  <div class="container">
    <app-virtual-machine></app-virtual-machine>
  </div>
</div>

现在在后台我们仍然有ng service在运行。如果你在命令行中检查,你可能会看到应用程序正在重新编译,因为我们已经做了这些新的更新。
ng serve re compile hot reload

当访问浏览器时,我们新创建的组件被渲染到了屏幕上。非常好!
angular js custom component


AngularJS组件教程总结

组件的概念存在于所有流行的前端框架中。作为开发者,我们的目标是创建可重复使用的业务逻辑和设计展示的重点容器。这是以组件的形式实现的。通过Angular,我们了解到整个应用程序的根组件是**。**这是在第一次使用Angular CLI构建你的Angular应用程序时为你创建的。我们不想直接修改这个组件,但是我们可以创建新的组件,这些组件可以在包含的app-root组件里面被引用。为了做到这一点,我们采取了以下步骤。

  • 使用新组件的名称创建一个新的文件夹
  • 在这个文件夹中使用该组件的名称添加一个Typescript文件
  • 添加一个HTML模板文件,该文件也使用该组件的名称
  • 使用@Component装饰器来配置该组件
  • 在模板文件中添加html标记
  • 在app.module.ts的声明数组中注册新的组件
  • 使用来使用这个新组件。