相对于组件的路径

为组件模板和样式表文件提供相对于组件的URL

组件通常都是引用外部的模板和样式表文件。 我们在@Component的元数据中通过templateUrlstyleUrls属性来标识出它们的位置:

@Component({
  selector: 'absolute-path',
  templateUrl: 'app/some.component.html',
  styleUrls:  ['app/some.component.css']
})

默认情况下,我们必须指定一个一直到应用程序根目录的完整路径。 我们称之为绝对路径,因为它绝对的以应用程序的根目录为基准。

使用绝对路径有两个问题:

  1. 我们不得不记住到应用程序根目录的完整路径。

  2. 当我们在应用的文件结构中移动这个组件时,将不得不更新这个URL

如果能用相对于组件类文件的路径来指定模板和样式表的位置,那么编写和维护组件就会变得容易得多。

没问题!

如果把应用构建成commonjs模块,并用一个合适的包加载器(比如systemjswebpack)加载那些模块,就可以用相对路径。 在下方可以学到原理。

Angular CLI(命令行界面)使用这些技术,并默认采用这里所说的组件相对路径方法。 用CLI用户可以跳过本章,或者继续阅读来了解它是怎么工作的。

组件相对路径

目标是把模板和样式表的URL指定为相对于组件类的路径,因此得名组件相对路径

成功的关键是遵循一个约定:把相对组件的文件放进众所周知的位置。

建议把组件的模板和组件特有的样式表文件作为组件类文件的“兄弟”。 这里在app目录下依次有SomeComponent的三个文件。

app
some.component.css
some.component.html
some.component.ts
...

当应用规模增长后,还会有更多的文件和目录,目录深度也会增加。 如果组件的所有文件总是像形影不离的兄弟那样共进退,那该多好啊!

设置moduleId

采用这种文件结构约定,可以为模板和样式表文件指定相对于组件类文件的位置 —— 只要简单的在@Component元数据中设置moduleId属性就可以了,就像这样:

moduleId: module.id,

templateUrlstyleUrls中把基准路径app/去掉了。结果是这样的:

@Component({
  moduleId: module.id,
  selector: 'relative-path',
  templateUrl: './some.component.html',
  styleUrls:  ['./some.component.css']
})

Webpack用户可能更喜欢一个替代方案

源码

参见live example / downloadable example,并从中下载源码或只在这里阅读相关源码。

  1. import { Component } from '@angular/core';
  2. ///////// Using Absolute Paths ///////
  3. @Component({
  4. selector: 'absolute-path',
  5. templateUrl: 'app/some.component.html',
  6. styleUrls: ['app/some.component.css']
  7. })
  8. export class SomeAbsoluteComponent {
  9. class = 'absolute';
  10. type = 'Absolute template & style URLs';
  11. path = 'app/path.component.html';
  12. }
  13. ///////// Using Relative Paths ///////
  14. @Component({
  15. moduleId: module.id,
  16. selector: 'relative-path',
  17. templateUrl: './some.component.html',
  18. styleUrls: ['./some.component.css']
  19. })
  20. export class SomeRelativeComponent {
  21. class = 'relative';
  22. type = 'Component-relative template & style URLs';
  23. path = 'path.component.html';
  24. }

附录:为什么组件相对路径不是默认方式

组件相对路径明显比绝对路径高级一点。 为什么Angular默认采用了绝对路径呢? 为什么我们不得不设置moduleId呢?Angular为什么不能自己设置它?

首先,如果只使用相对路径而省略掉moduleId,我们来看看会发生什么。

EXCEPTION: Failed to load some.component.html

EXCEPTION: Failed to load some.component.html

Angular找不到这个文件,所以它抛出一个错误。

为什么Angular不能相对于组件类文件的路径来自动计算模板和样式表的URL呢?

因为如果没有开发人员的帮助,组件的位置是检测不到的。 Angular应用可能被用多种方式加载:独立文件、SystemJS包、CommonJS包等等。 用来生成模块的格式可以是任何格式。 甚至可能完全没有写成模块化代码。

由于存在这么多打包和模块加载策略,所以Angular不可能知道在运行期这些文件的正确位置。

Angular能够确定的唯一的位置是首页index.html的URL,也就是应用的根目录。 所以,默认情况下,它只能计算相对于index.html的模板和样式表路径。 这就是为什么我们以前用app/基准路径的前缀来写文件的URL。

但是,如果遵循建议的指导原则,用commonjs格式编写模块,并使用一个不错的模块加载器, 我们要知道,有一个可用的半全局变量module.id,它包含组件类模块文件的绝对URL。

这种认知让我们得以通过设置moduleId来告诉Angular组件类文件在哪里:

moduleId: module.id,

Webpack: 加载模板和样式表

Webpack开发者可以采用moduleId的另一个替代方案。

通过让组件元数据中的templatestyles / styleUrls属性以./开头,并使其指向相对于组件的URL,可以在运行期间为它们加载模板和样式表。

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

import '../../public/css/styles.css';

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

Webpack将会在幕后执行一次require来加载这些模板和样式。要了解更多,请参阅这里

参见Webpack简介