React 开发者,学习 Angular

@高效码农  November 24, 2022

在 Angular 中创建组件

假设我们要创建一个CustomButton组件。当我们在 React 中创建这个组件时,它看起来类似于:

//imports

export const CustomButton = () => {
  const onClick= () => {}

  return (
<button    
        onClick={onClick}
            className=”button-class”>
         Click me
      </button>
  )
};

我们有组件的名称、它的标记和它可以在 JSX 中处理的逻辑——如果我们使用的是 typescript 扩展文件,则为 TSX。

在 Angular 中,要创建完全相同的组件,我们可以使用以下命令:

ng generate component custom-button

上面的命令将创建一个文件夹,其中包含三个文件: ustom-button.component.html、custom-button.component.scss和custom-button.component.ts。Angular 如何处理这三个文件以将它们作为一个组件使用?该组件的配置在.component.ts文件中。它有@Component装饰器告诉 Angular 如何处理和实例化组件以及在哪里找到每一层信息。这与 Angular 中的示例相同:

//custom-button.component.html

<button
    class="button-class"
    (click)="onClick()">
    Click me
  </button>

 

//custom-button.component.ts
//imports 

@Component({
  selector: 'custom-button',
  templateUrl: './custom-button.component.html',
  styleUrls: ['custom-button.component.scss]
})
export class CustomButton {
  onClick = () => {}
}

如您所见,它们看起来非常相似,但由于 React 使用 JSX 而 Angular 使用 HTML 作为标记,因此存在一些明显的语法差异:

  • 在 Angular 中,类由属性类设置。
  • Angular 组件在浏览器检查器中可见。在这个例子中,我们会看到类似的东西:
<custom-button class=”button-class”><button>Click me</button><custom-button>
  • 请注意,Angular 在代表组件本身的标记中创建了一个附加层。在 React 中,你会直接看到按钮。

向组件添加属性

在 React 中,我们使用 props 使组件可定制和动态。例如,我们可能会传递property text=“Click me”使按钮更通用:

export const CustomButton = ({text}) => {
  const onClick= () => {}

  return (
<button ...>
         {text}
      </button>
  )
};

在 Angular 中,我们需要@Input()在 .ts 文件中使用装饰器并初始化它:

@Component({
  selector: 'custom-button',
  templateUrl: './custom-button.component.html',
  styleUrls: ['custom-button.component.scss]
})
export class CustomButton {
  @Input() text = ‘’ //Note that it is mandatory to initialise it either here or in the class constructor
  onClick = () => {}
}

并在 HTML 中使用双括号:

<button
    class="button-class"
    (click)="onClick()">
    {{ text }}
  </button>

调用父组件函数

当使用纯 UI 组件时,我们可能希望将一个函数从父组件传递给子组件。在 React 中,它在子组件中看起来像这样:

export const CustomButton = ({onClick}) => {
  handleClick = () => {
      //some internal logic
    onClick();//function passed from the parent component
  }

  return (
<button    
        onClick={handleClick}
            className=”button-class”>
         Click me
      </button>
  )
};

在 Angular 中,我们会使用@Output()装饰器:

@Component({
  selector: 'custom-button',
  templateUrl: './custom-button.component.html',
  styleUrls: ['custom-button.component.scss]
})
export class CustomButton {
  @Output() onClick: new EventEmitter<any>();

  handleClick = () => {
    //some logic
    this.onClick.emit()//here we can also pass the event or other data that we want to receive in the parent component
  }
}

创建一个 NgModule

我们现在对如何创建 Angular 组件有了一些了解,但是它在 Angular 生态系统中的什么位置?当我们在 Angular 中创建组件时,需要在 NgModule 中声明它。NgModule 是一个代码块,它有自己的配置、路由和@NgModule装饰器指定的依赖项,可以通过路由延迟加载。当您来自 React 时,乍一听这可能有点棘手,但让我们通过一个例子来看一下。当我们启动一个 Angular 项目时,它会附带一个名为的模块app.module.ts,其中包含以下基础知识:

// imports

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

这是最基本的 NgModule:

  • declarations 数组指示它将包含哪些表示组件,例如,如果我们要在此模块中加载自定义按钮,我们将在此处包含它。
  • 导入:加载当前模块所需的模块。在内部,Angular 将模块的服务提供者列表添加到应用程序根注入器中。在这种情况下,BrowserModule具有特定于浏览器的服务,例如 DOM 呈现、清理和位置。
  • Providers:当前模块拥有的服务依赖列表。例如,这可以是加载数据的服务或处理身份验证的服务。
  • 导出:此处未显示,但它是一个数组,您可以在其中导出当前模块的组件,以便能够在其他模块中使用它们。
  • Bootstrap:Angular 将插入的根组件index.html。

为什么我们需要这些模块?

应用程序总是被划分为可维护性的功能块。在 React 中,这个划分由开发人员决定,没有特定的约定可循;但是,在 Angular 中,代码可以分为 NgModules。装饰器指定了这部分代码的@NgModule配置,包括它的外部依赖,它的内部依赖应该如何注入,它应该如何编译。这会创建具有自己的 UI 组件和路由的内聚代码块。

并非所有模块都将成为按路线显示的展示组件。非演示组件内置模块的一个示例是RouterModuleAngular 提供的一个经常使用的模块,用于定义现有路由以及它们应该加载哪些组件。它允许您跟踪当前页面是否对应于特定路由 ( RouterActiveLink) 或 URL 是否需要某些条件才能访问 ( CanActivate)。
Angular 团队也在致力于简化此配置,最终消除对 NgModule 的需求,并通过路由进行此配置,我们将在下一节中讨论。

减少 NgModules 需求的新 API

为了改进 tree-shaking 并降低复杂性,Angular 正在致力于创建新的 API,其中:

  • 依赖注入将直接使用 providers 和 providers 数组处理。RouterModule.forRoot(routes, config)与其在 NgModule中配置 Angular 路由器,不如在路由器中配置。
  • Bootstrapping——当前在 NgModule 中配置——将由一个新bootstrapApplication函数处理。
  • importProvidersFrom功能将允许与以前的 NgModules 兼容。
  • 延迟加载组件不仅适用于 NgModules,而且适用于单个组件和子路由。
  • 每个路由的依赖关系可以单独指定,而不是按模块指定。


评论已关闭