在 中,bookMarkup 函数使用 Book 元素创建标记。Book 组件的代码如清单 3 所示。
清单 3. book 组件 (components/book.js)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| import React from 'react';
const Book = ({
item,
displayMode,
}) => {
const styles = {
links: {
marginTop: '20px',
},
link: {
padding: '25px',
},
image: {
boxShadow: '3px 3px 3px #686868',
marginBottom: '15px',
},
};
const linkMarkup = (currentItem, link) => (
<div style={styles.links}>
<a href={link} style={styles.link}>
{currentItem.volumeInfo.title}
</a>
</div>
);
const thumbnailMarkup = (currentItem, link) => (
<a href={link} style={styles.link}>
<img src={currentItem.volumeInfo.imageLinks.thumbnail}
style={styles.image}
role="presentation" />
</a>
);
const link = item.volumeInfo.canonicalVolumeLink;
return displayMode === 'THUMBNAIL' ?
thumbnailMarkup(item, link) :
linkMarkup (item, link);
};
Book.propTypes = {
item: React.PropTypes.object.isRequired,
displayMode: React.PropTypes.string.isRequired,
};
export default Book;
|
Book 组件将图书显示为链接或缩略图。item 和 displayMode 属性来自 Books 组件,如 所示。
此组件完善了使用 React 和 Redux 的图书搜索应用程序的实现。React 不是您用于 Redux 的组件框架的唯一选择。接下来,将会了解如何结合使用 Redux 和 Angular 创建同一个应用程序。(如果仅使用 React,可以跳到 部分。)
结合使用 Redux 和 Angular示例代码存储库可以从作者的 GitHub 获取图书搜索应用程序的两个版本的完整示例代码。
图 2 给出了图书搜索应用程序的 Angular 2(下文简称 Angular)版本。
图 2. 图书搜索应用程序的 Angular 版本
为什么选择 TypeScript?Angular 支持 3 种语言:JavaScript、 和 Dart。我为图书搜索应用程序选择了 TypeScript,这主要是因为 Angular 文档的 TypeScript 版本最完整。
像 React 一样(但不同于 Angular 1),Angular 是一个基于组件的框架。因此从理论上讲,我应该能有效地将 React 组件替换为 Angular 组件,并重用 React 版本的 reducer、操作和存储。事实证明该理论切实可行。
重要说明:图书搜索应用程序的代码不适用于 RC5 之前的任何 Angular 版本。
设置图书搜索应用程序的 Angular 版本的 HTML 如清单 4 所示。
清单 4. 该应用程序的 HTML (index.html)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <html>
<head>
<title>Book Search</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<app>Loading...</app>
</body>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="dist/bundle.js"></script>
</html>
|
清单 4 中的 HTML 拉入了一些填充信息和该应用程序的 TypeScript。清单 5 给出了应用程序的模块。
清单 5. 该应用程序的模块 (app/app.module.ts)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import App from './components/app.component';
import Book from './components/book.component';
import Books from './components/books.component';
import Controls from './components/controls.component';
import DisplayMode from './components/displayMode.component';
import History from './components/history.component';
import StateViewer from './components/stateviewer.component';
import TopicSelector from './components/topicselector.component';
@NgModule({
bootstrap: [ App ],
declarations: [
App,
Book,
Books,
Controls,
DisplayMode,
History,
StateViewer,
TopicSelector,
],
imports: [
BrowserModule,
FormsModule,
],
})
export class AppModule { }
|
清单 5 的代码定义了一个 Angular 模块。@NgModule 是一个 TypeScript 注释。(Angular 的 TypeScript 版本中大量使用了注释。)@NgModule 注释是 Angular RC5 中的一项新功能。
在实现 Angular 应用程序时,必须声明模块中的所有组件。清单 5 的代码导入了浏览器模块,浏览器中运行的所有 Angular 应用程序都会导入该模块。该模块也是 @NgModule 注释的来源。
我没有在图书搜索应用程序中使用表单,但显然,我必须导入表单模块 (FormsModule);如果不导入,则会获得以下错误消息:
Can't bind to ngModel since it isn't a known property of input.
该错误消息没有提供任何线索来表明需要导入表单模块;堆栈溢出为我提供了解决方案。
样板的最后一部分是应用程序的入口点 (app/main.ts):
1
2
3
4
| import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
|
main.ts 代码启动 Angular 应用程序。
它负责运行图书搜索应用程序的 Angular 版本的样板。现在我将展示该应用程序的 Angular 组件。 |