开发工具分享
  • 首页
  • 计算科学
  • 文化旅游
  • 项目和网站
    • OSSEZ 计算技术
    • USRealEstate 社区
    • 地区文化
    • CWIKI.US
    • BUG.OSSEZ.COM
    • RSS.OSSEZ.COM
Computer Science
Computer Science

Akka 介绍

欢迎使用 Akka,Akka 是一套被用来在在多处理器核心和网络之间被设计可扩展和具有相关弹性的开源工具集。Akka 允许你更加关注商业需求而不是书写低级别的代码来提供可靠性,容错率和高性能。 很多常用的设计实践和已经接受的程序模型不能解决一些重要的挑战,这些挑战通常是现代计算机体系结构中固有的。为了让项目取得成功,分布式系统必须能够应付一些环境出现的问题,例如组件崩溃不能响应,发送的消息没有痕迹的就丢失了,为了让分布式系统能够成功的运行,以及网络延迟和波动等问题。这些问题在具有很好管理和监控环境下的数据中心经常会发生,针对虚拟架构环境就更加容易出现上面的这些问题了。 为了帮助你处理上面提到这些现实的问题,Akka 提供了: 不使用低级并发结构的多线程,例如原子或锁;让你免于考虑内存可见性的问题。 系统和组件之间的远程通讯透明性; 让你免于属性和维护复杂的网络代码。 一个高可用性的集群架构,这个集群具有相当的弹性,在线方式;让你真正能够部署一个反应系统。 Reactive System. A reactive system is a system that responds (reacts) to external events。 反应系统是一个能对外部事件做出相应反应的系统。早期所谓的reactive system是软件系统的一个分支,意思正如它的名字所描述的。后来这个概念被美国的David Harel明确下来,其最主要部分是描述反应行为。 什么是反应行为呢?下面看一个转换系统的例子 输入(开始)->软件系统(经过一段时间后停止运行)->(然后)输出 例子中用户把数据输入给计算机,软件对这些数据经过一段时间的计算,最后给出输出结果,我们可以看作一个会计的月结算或者一个测量的统计数据。 能够得知,输入数据经过特定的规则被转换,并且在结束计算过程以后给出结果。而reactive system却与此相反。 与转换系统相反,在reactive system里往往没有明确的时序安排。总体来讲,reactive system表示的是不限制运行时间的系统,这其中要和外部环境相互作用,也就是在外部刺激上的反应(reactive),例如和不同使用者或者外部的硬件等,但是也包括内部发生的交流行为,因为reactive system是被集成在并行运行的分布式系统的规则中的。 例如,一个计算机的操作系统是这样一个reactive system,它不会停止运行,而总是反应用户给的输入,并且计算机中的各个组件之间要进行交流。 在电信领域,生产控制或者在硬件环境的构造(嵌入式系统)中还存在很多这样的例子。在信息系统中,也就是基于数据库的应用系统中也要用到 reactive system。在给一个典型的例子就是警报系统(Early Warning System). Akka 使用 actor 抽象模型能够让 Akka 更加容易的创建正确的并发,并行的分布式系统。actor 模型贯穿整个 Akka 的库,能够让你更加容易的理解和使用它们,并且能够保证更好的完整性。因此 Akka 提供了一个深度的整合和集成,如果你无法通过选择库来解决个别问题的时候,你可以尝试将这些整合在一起。 通过学习 Akka 和如何使用 actor 模型,你将访问到庞大和深入的工具集用来解决分布式并行系统中遇到的困难和挑战,通过统一的编程模型,其中所有的东西都能够紧密和高效的组合在了一起。   https://www.cwiki.us/display/AkkaZH/Introduction+to+Akka

2019年07月22日 0Comments 1089Browse 0Like Read more
Computer Science

Travis CI eval ./gradlew assemble 错误

问题 在进行 Travis CI 进行集成编译的时候出现错误。 <-------------> 0% WAITINGThe command "eval ./gradlew assemble " failed. Retrying, 2 of 3. FAILURE: Build failed with an exception. * What went wrong: Task 'assemble' not found in root project 'asciidoc-docs'. * Try: Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 0s <-------------> 0% WAITINGThe command "eval ./gradlew assemble " failed. Retrying, 3 of 3. 具体的错误信息如下: BUILD FAILED in 8s <-------------> 0% WAITINGThe command "eval ./gradlew assemble " failed. Retrying, 2 of 3. FAILURE: Build failed with an exception. * What went wrong: Task 'assemble' not found in root project 'asciidoc-docs'. * Try: Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 0s <-------------> 0% WAITINGThe command "eval ./gradlew assemble " failed. Retrying, 3 of 3. FAILURE: Build failed with an exception. * What went wrong: Task 'assemble' not found in root project 'asciidoc-docs'. * Try: Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD…

2019年07月13日 0Comments 1069Browse 0Like Read more
Computer Science

Travis CI Could not find or load main class org.gradle.wrapper.GradleWrapperMain 错误

问题 在 Travis CI 编译的时候出现 Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain 错误。 详细的错误日志为: Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain The command "eval ./gradlew assemble " failed. Retrying, 2 of 3. Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain The command "eval ./gradlew assemble " failed. Retrying, 3 of 3. Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain The command "eval ./gradlew assemble " failed 3 times. The command "./gradlew assemble" failed and exited with 1 during . Your build has been stopped.   解决方法 看看你提交的代码中 gradle 文件夹有没有提交上去。 如果没有提交这个文件夹的话,需要将源代码中的 gradle 提交到代码库上。

2019年07月13日 0Comments 1204Browse 0Like Read more
Computer Science

HyperSQL 链接参数中文件的路径

如果我们在系统中配置下面的连接参数: spring.datasource.url=jdbc:hsqldb:file:~/db/cwiki-us-jpetstore 我们怎么知道 hsqldb 数据库的存储路径在哪里?   请参考下面的解答: 在 Windows 系统中,如果你登录的用户名为 yhu 的话。 那么这个数据库文件在 :C:\Users\yhu\db 中存储。

2019年06月06日 0Comments 1008Browse 0Like Read more
Computer Science

Maven 在 pom.xml 文件中配置 repositories 仓库

如果你希望在你的项目中使用独立的 repositories 。 例如,你希望配置使用自己的 https://maven.ossez.com/repository/internal 作为仓库。 例如,修改后的 pom.xml 文件如下: <repositories> <repository> <id>maven-ossez</id> <name>OSSEZ Repository</name> <url>https://maven.ossez.com/repository/internal</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>maven-ossez</id> <name>OSSEZ Repository</name> <url>https://maven.ossez.com/repository/internal</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories>

2019年06月06日 0Comments 1016Browse 0Like Read more
Computer Science

Flyway Validate failed: Migration checksum mismatch for migration version 1.0.0.01 错误

在运行系统的时候出现错误: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Validate failed: Migration checksum mismatch for migration version 1.0.0.01 -> Applied to database : 1062144176 -> Resolved locally : 1432425380   尝试使用命令: > mvn flyway:migrate 来对校验进行合并  

2019年06月06日 0Comments 1432Browse 1Like Read more
Computer Science

Angular 服务

英雄指南的 HeroesComponent 目前获取和显示的都是模拟数据。 本节课的重构完成之后,HeroesComponent 变得更精简,并且聚焦于为它的视图提供支持。这也让它更容易使用模拟服务进行单元测试。 如果你希望从 GitHub 上查看我们提供测试的源代码,你可以访问下面的链接:https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-hero-services 为什么需要服务 组件不应该直接获取或保存数据,它们不应该了解是否在展示假数据。 它们应该聚焦于展示数据,而把数据访问的职责委托给某个服务。 本节课,你将创建一个 HeroService,应用中的所有类都可以使用它来获取英雄列表。 不要使用 new 来创建此服务,而要依靠 Angular 的依赖注入机制把它注入到 HeroesComponent 的构造函数中。 服务是在多个“互相不知道”的类之间共享信息的好办法。 你将创建一个 MessageService,并且把它注入到两个地方: HeroService 中,它会使用该服务发送消息。 MessagesComponent 中,它会显示其中的消息。 创建 HeroService 使用 Angular CLI 创建一个名叫 hero 的服务。 ng generate service hero 该命令会在src/app/hero.service.ts中生成HeroService类的骨架。HeroService类的代码如下: src/app/hero.service.ts (new service) import { Injectable } from '@angular/core'; @Injectable({   providedIn: 'root', }) export class HeroService {   constructor() { } } @Injectable() 服务 注意,这个新的服务导入了 Angular 的 Injectable 符号,并且给这个服务类添加了 @Injectable() 装饰器。 它把这个类标记为依赖注入系统的参与者之一。HeroService 类将会提供一个可注入的服务,并且它还可以拥有自己的待注入的依赖。 目前它还没有依赖,但是很快就会有了。 @Injectable() 装饰器会接受该服务的元数据对象,就像 @Component() 对组件类的作用一样。 获取英雄数据 HeroService 可以从任何地方获取数据:Web 服务、本地存储(LocalStorage)或一个模拟的数据源。 从组件中移除数据访问逻辑,意味着将来任何时候你都可以改变目前的实现方式,而不用改动任何组件。 这些组件不需要了解该服务的内部实现。 这节课中的实现仍然会提供模拟的英雄列表。 导入 Hero 和 HEROES。 import { Hero } from './hero'; import { HEROES } from './mock-heroes'; 添加一个 getHeroes 方法,让它返回模拟的英雄列表。 getHeroes(): Hero[] {   return HEROES; } 提供(provide) HeroService 在要求 Angular 把 HeroService 注入到 HeroesComponent 之前,你必须先把这个服务提供给依赖注入系统。稍后你就要这么做。 你可以通过注册提供商来做到这一点。提供商用来创建和交付服务,在这个例子中,它会对 HeroService 类进行实例化,以提供该服务。 现在,你需要确保 HeroService 已经作为该服务的提供商进行过注册。 你要用一个注入器注册它。注入器就是一个对象,负责在需要时选取和注入该提供商。 默认情况下,Angular CLI 命令 ng generate service 会通过给 @Injectable 装饰器添加元数据的形式,用根注入器将你的服务注册成为提供商。 如果你看看 HeroService 紧前面的 @Injectable() 语句定义,就会发现 providedIn 元数据的值是 'root': @Injectable({   providedIn: 'root', }) @ Injectable ({ providedIn: 'root', }) 当你在顶层提供该服务时,Angular 就会为 HeroService 创建一个单一的、共享的实例,并把它注入到任何想要它的类上。 在 @Injectable 元数据中注册该提供商,还能允许 Angular 通过移除那些完全没有用过的服务来进行优化。 要了解关于提供商的更多知识,参见提供商部分。 要了解关于注入器的更多知识,参见依赖注入指南。 现在 HeroService 已经准备好插入到 HeroesComponent 中了。 这是一个过渡性的代码范例,它将会允许你提供并使用 HeroService。此刻的代码和最终代码相差很大。 修改 HeroesComponent 打开 HeroesComponent 类文件。 删除 HEROES 的导入语句,因为你以后不会再用它了。 转而导入 HeroService。 src/app/heroes/heroes.component.ts (import HeroService) import { HeroService } from '../hero.service'; 把 heroes 属性的定义改为一句简单的声明。 heroes: Hero[]; 注入 HeroService 往构造函数中添加一个私有的 heroService,其类型为 HeroService。 constructor(private heroService: HeroService) { } 这个参数同时做了两件事:1. 声明了一个私有 heroService 属性,2. 把它标记为一个 HeroService 的注入点。 当 Angular 创建 HeroesComponent 时,依赖注入系统就会把这个 heroService 参数设置为 HeroService 的单例对象。 添加 getHeroes() 创建一个函数,以从服务中获取这些英雄数据。 getHeroes(): void {   this.heroes = this.heroService.getHeroes(); } 在 ngOnInit 中调用它 你固然可以在构造函数中调用 getHeroes(),但那不是最佳实践。 让构造函数保持简单,只做初始化操作,比如把构造函数的参数赋值给属性。 构造函数不应该做任何事。 它当然不应该调用某个函数来向远端服务(比如真实的数据服务)发起 HTTP 请求。 而是选择在 ngOnInit 生命周期钩子中调用 getHeroes(),之后交由 Angular 处理,它会在构造出 HeroesComponent 的实例之后的某个合适的时机调用 ngOnInit。 ngOnInit() {   this.getHeroes(); } 查看运行效果 刷新浏览器,该应用仍运行的一如既往。 显示英雄列表,并且当你点击某个英雄的名字时显示出英雄详情视图。 可观察(Observable)的数据 HeroService.getHeroes() 的函数签名是同步的,它所隐含的假设是 HeroService 总是能同步获取英雄列表数据。 而 HeroesComponent 也同样假设能同步取到 getHeroes() 的结果。 this.heroes = this.heroService.getHeroes(); 这在真实的应用中几乎是不可能的。 现在能这么做,只是因为目前该服务返回的是模拟数据。 不过很快,该应用就要从远端服务器获取英雄数据了,而那天生就是异步操作。 HeroService 必须等服务器给出响应, 而 getHeroes() 不能立即返回英雄数据, 浏览器也不会在该服务等待期间停止响应。 HeroService.getHeroes() 必须具有某种形式的异步函数签名。 它可以使用回调函数,可以返回 Promise(承诺),也可以返回 Observable(可观察对象)。 这节课,HeroService.getHeroes() 将会返回 Observable,因为它最终会使用 Angular 的 HttpClient.get 方法来获取英雄数据,而 HttpClient.get() 会返回 Observable。 可观察对象版本的 HeroService Observable 是 RxJS 库中的一个关键类。 在稍后的 HTTP 教程中,你就会知道 Angular HttpClient 的方法会返回 RxJS 的 Observable。 这节课,你将使用 RxJS 的 of() 函数来模拟从服务器返回数据。 打开 HeroService 文件,并从 RxJS 中导入 Observable 和 of 符号。 src/app/hero.service.ts (Observable imports) import { Observable, of } from 'rxjs'; 把 getHeroes 方法改成这样: getHeroes(): Observable<Hero[]> {   return of(HEROES); } of(HEROES)会返回一个Observable<Hero[]>,它会发出单个值,这个值就是这些模拟英雄的数组。 在 HTTP 教程中,你将会调用 HttpClient.get<Hero[]>() 它也同样返回一个 Observable<Hero[]>,它也会发出单个值,这个值就是来自 HTTP 响应体中的英雄数组。 在 HeroesComponent 中订阅 HeroService.getHeroes 方法之前返回一个 Hero[], 现在它返回的是 Observable<Hero[]>。 你必须在 HeroesComponent 中也向本服务中的这种形式看齐。 找到 getHeroes 方法,并且把它替换为如下代码(和前一个版本对比显示): heroes.component.ts (Observable) getHeroes(): void {   this.heroService.getHeroes()       .subscribe(heroes => this.heroes = heroes); } heroes.component.ts (Original) getHeroes(): void {   this.heroes = this.heroService.getHeroes(); } Observable.subscribe() 是关键的差异点。 上一个版本把英雄的数组赋值给了该组件的 heroes 属性。 这种赋值是同步的,这里包含的假设是服务器能立即返回英雄数组或者浏览器能在等待服务器响应时冻结界面。 当 HeroService 真的向远端服务器发起请求时,这种方式就行不通了。 新的版本等待 Observable 发出这个英雄数组,这可能立即发生,也可能会在几分钟之后。 然后,subscribe 函数把这个英雄数组传给这个回调函数,该函数把英雄数组赋值给组件的 heroes属性。 使用这种异步方式,当 HeroService 从远端服务器获取英雄数据时,就可以工作了。 显示消息 在这一节,你将 添加一个 MessagesComponent,它在屏幕的底部显示应用中的消息。 创建一个可注入的、全应用级别的 MessageService,用于发送要显示的消息。 把 MessageService 注入到 HeroService 中。 当 HeroService 成功获取了英雄数据时显示一条消息。 创建 MessagesComponent 使用 CLI 创建 MessagesComponent。 ng generate component messages CLI 在 src/app/messages 中创建了组件文件,并且把 MessagesComponent 声明在了 AppModule 中。 修改 AppComponent 的模板来显示所生成的 MessagesComponent: /src/app/app.component.html <h1>{{title}}</h1> <app-heroes></app-heroes> <app-messages></app-messages> 你可以在页面的底部看到来自的 MessagesComponent 的默认内容。 创建 MessageService 使用 CLI 在 src/app 中创建 MessageService。…

2019年05月30日 0Comments 1011Browse 0Like Read more
Computer Science

Angular 主从组件

此刻,HeroesComponent 同时显示了英雄列表和所选英雄的详情。 把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。 你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。 本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 HeroDetailComponent。 HeroesComponent 将仅仅用来表示英雄列表。 HeroDetailComponent 将用来表示所选英雄的详情。 你可以访问下面的链接 https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail 从 GitHub 上查看我们提供源代码。 制作 HeroDetailComponent 使用 Angular CLI 生成一个名叫 hero-detail 的新组件。 ng generate component hero-detail 这个命令会做这些事: 创建一个目录 src/app/hero-detail. 在这个目录中会生成四个文件: 作为组件样式的 CSS 文件。 作为组件模板的 HTML 文件。 存放组件类 HeroDetailComponent 的 TypeScript 文件。 HeroDetailComponent 类的测试文件。 该命令还会把 HeroDetailComponent 添加到 src/app/app.module.ts 文件中 @NgModule 的 declarations 列表中。 编写模板 从 HeroesComponent 模板的底部把表示英雄详情的 HTML 代码剪切粘贴到所生成的 HeroDetailComponent 模板中。 所粘贴的 HTML 引用了 selectedHero。 新的 HeroDetailComponent 可以展示任意英雄,而不仅仅所选的。因此还要把模板中的所有 selectedHero 替换为 hero。 完工之后,HeroDetailComponent 的模板应该是这样的: src/app/hero-detail/hero-detail.component.html <div *ngIf="hero">   <h2>{{hero.name | uppercase}} Details</h2>   <div><span>id: </span>{{hero.id}}</div>   <div>     <label>name:       <input [(ngModel)]="hero.name" placeholder="name"/>     </label>   </div> </div> 添加 @Input() hero 属性 HeroDetailComponent 模板中绑定了组件中的 hero 属性,它的类型是 Hero。 打开 HeroDetailComponent 类文件,并导入 Hero 符号。 src/app/hero-detail/hero-detail.component.ts (import Hero) import { Hero } from '../hero'; hero 属性必须是一个带有 @Input() 装饰器的输入属性,因为外部的 HeroesComponent 组件将会绑定到它。就像这样: <app-hero-detail [hero]="selectedHero"></app-hero-detail> 修改 @angular/core 的导入语句,导入 Input 符号。 src/app/hero-detail/hero-detail.component.ts (import Input) import { Component, OnInit, Input } from '@angular/core'; 添加一个带有 @Input() 装饰器的 hero 属性。 @Input() hero: Hero; 这就是你要对 HeroDetailComponent 类做的唯一一项修改。 没有其它属性,也没有展示逻辑。这个组件所做的只是通过 hero 属性接收一个英雄对象,并显示它。 显示 HeroDetailComponent HeroesComponent 仍然是主从视图。 在你从模板中剪切走代码之前,它自己负责显示英雄的详情。现在它要把这个职责委托给 HeroDetailComponent 了。 这两个组件将会具有父子关系。 当用户从列表中选择了某个英雄时,父组件 HeroesComponent 将通过把要显示的新英雄发送给子组件 HeroDetailComponent,来控制子组件。 你不用修改 HeroesComponent 类,但是要修改它的模板。 修改 HeroesComponent 的模板 HeroDetailComponent 的选择器是 'app-hero-detail'。 把 <app-hero-detail> 添加到 HeroesComponent 模板的底部,以便把英雄详情的视图显示到那里。 把 HeroesComponent.selectedHero 绑定到该元素的 hero 属性,就像这样: heroes.component.html (HeroDetail binding) <app-hero-detail [hero]="selectedHero"></app-hero-detail> [hero]="selectedHero" 是 Angular 的属性绑定语法。 这是一种单向数据绑定。从 HeroesComponent 的 selectedHero 属性绑定到目标元素的 hero 属性,并映射到了 HeroDetailComponent 的 hero 属性。 现在,当用户在列表中点击某个英雄时,selectedHero 就改变了。 当 selectedHero 改变时,属性绑定会修改 HeroDetailComponent 的 hero 属性,HeroDetailComponent 就会显示这个新的英雄。 修改后的 HeroesComponent 的模板是这样的: heroes.component.html <h2>My Heroes</h2> <ul class="heroes">   <li *ngFor="let hero of heroes"     [class.selected]="hero === selectedHero"     (click)="onSelect(hero)">     <span class="badge">{{hero.id}}</span> {{hero.name}}   </li> </ul> <app-hero-detail [hero]="selectedHero"></app-hero-detail> 浏览器刷新,应用又像以前一样开始工作了。 修改了什么? 像以前一样,一旦用户点击了一个英雄的名字,该英雄的详情就显示在了英雄列表下方。 现在,HeroDetailComponent 负责显示那些详情,而不再是 HeroesComponent。 把原来的 HeroesComponent 重构成两个组件带来了一些优点,无论是现在还是未来: 你通过缩减 HeroesComponent 的职责简化了该组件。 你可以把 HeroDetailComponent 改进成一个功能丰富的英雄编辑器,而不用改动父组件 HeroesComponent。 你可以改进 HeroesComponent,而不用改动英雄详情视图。 将来你可以在其它组件的模板中重复使用 HeroDetailComponent。 查看最终代码 你的应用应该变成了这样 在线例子 / 下载范例。本页所提及的代码文件如下: 如果你想直接在 stackblitz 运行本页中的例子,请单击链接:https://stackblitz.com/github/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail 本页中所提及的代码如下:https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail 对应的文件列表和代码链接如下: 文件名 源代码 src/app/hero-detail/hero-detail.component.ts https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/hero-detail/hero-detail.component.ts src/app/hero-detail/hero-detail.component.html https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/hero-detail/hero-detail.component.html src/app/heroes/heroes.component.html https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/heroes/heroes.component.html src/app/app.module.ts https://github.com/cwiki-us-angular/cwiki-us-angular-tour-of-heroes-master-detail/blob/master/src/app/app.module.ts 小结 你创建了一个独立的、可复用的 HeroDetailComponent 组件。 你用属性绑定语法来让父组件 HeroesComponent 可以控制子组件 HeroDetailComponent。 你用 @Input 装饰器来让 hero 属性可以在外部的 HeroesComponent 中绑定。 https://www.cwiki.us/pages/viewpage.action?pageId=47841998

2019年05月29日 0Comments 1007Browse 0Like Read more
Computer Science

Angular 显示英雄列表

在本页面,你将扩展《英雄指南》应用,让它显示一个英雄列表, 并允许用户选择一个英雄,查看该英雄的详细信息。 创建模拟(mock)英雄数据 你需要一些英雄数据以供显示。 最终,你会从远端的数据服务器获取它。但是目前,你需要创建一些模拟英雄(some mock heroes),并假设这些数据是从远程服务器上获取的。 在 src/app/ 文件夹中创建一个名叫 mock-heroes.ts 的文件。 定义一个包含十个英雄的常量数组 HEROES,并导出它。 该文件是这样的。 src/app/mock-heroes.ts import { Hero } from './hero'; export const HEROES: Hero[] = [   { id: 11, name: 'Mr. Nice' },   { id: 12, name: 'Narco' },   { id: 13, name: 'Bombasto' },   { id: 14, name: 'Celeritas' },   { id: 15, name: 'Magneta' },   { id: 16, name: 'RubberMan' },   { id: 17, name: 'Dynama' },   { id: 18, name: 'Dr IQ' },   { id: 19, name: 'Magma' },   { id: 20, name: 'Tornado' } ]; 显示英雄 你要在 HeroesComponent 的顶部显示这个英雄列表。 打开 HeroesComponent 类文件,并导入模拟的 HEROES 数据。 src/app/heroes/heroes.component.ts import { HEROES } from '../mock-heroes'; 往类中添加一个 heroes 属性,这样可以暴露出这些英雄,以供绑定。 src/app/heroes/heroes.component.ts export class HeroesComponent implements OnInit {   heroes = HEROES; 使用 *ngFor 列出这些英雄 打开 HeroesComponent 的模板文件,并做如下修改: 在顶部添加 <h2> 然后添加表示无序列表的 HTML 元素(<ul>) 在 <ul> 中插入一个 <li> 元素,以显示单个 hero 的属性。 点缀上一些 CSS 类(稍后你还会添加更多 CSS 样式)。 完成后应该如下显示: heroes.component.html heroes.component.html (heroes template) content_copy <h2>My Heroes</h2> <ul class="heroes">   <li>     <span class="badge">{{hero.id}}</span> {{hero.name}}   </li> </ul> 现在,把 <li> 修改成这样: <li *ngFor="let hero of heroes"> *ngFor 是一个 Angular 的复写器(repeater)指令。 它会为列表中的每项数据复写它的宿主元素。 在这个例子中 <li> 就是 *ngFor 的宿主元素 heroes 就是来自 HeroesComponent 类的列表。 当依次遍历这个列表时,hero 会为每个迭代保存当前的英雄对象。 不要忘了 ngFor 前面的星号(*),它是该语法中的关键部分。 浏览器刷新之后,英雄列表出现了。 给英雄们应用样式表 英雄列表应该富有吸引力,并且当用户把鼠标移到某个英雄上和从列表中选中某个英雄时,应该给出视觉反馈。 在教程的第一章,你曾在 styles.css 中为整个应用设置了一些基础的样式。 但那个样式表并不包含英雄列表所需的样式。 固然,你可以把更多样式加入到 styles.css,并且放任它随着你添加更多组件而不断膨胀。 但还有更好的方式。你可以定义属于特定组件的私有样式,并且让组件所需的一切(代码、HTML 和 CSS)都放在一起。 这种方式让你在其它地方复用该组件更加容易,并且即使全局样式和这里不一样,组件也仍然具有期望的外观。 你可以用多种方式定义私有样式,或者内联在 @Component.styles 数组中,或者在 @Component.styleUrls 所指出的样式表文件中。 当 CLI 生成 HeroesComponent 时,它也同时为 HeroesComponent 创建了空白的 heroes.component.css 样式表文件,并且让 @Component.styleUrls 指向它,就像这样: src/app/heroes/heroes.component.ts @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) 打开 heroes.component.css 文件,并且把 HeroesComponent 的私有 CSS 样式粘贴进去。 你可以在本指南底部的查看最终代码中找到它们。 @Component 元数据中指定的样式和样式表都是局限于该组件的。 heroes.component.css 中的样式只会作用于 HeroesComponent,既不会影响到组件外的 HTML,也不会影响到其它组件中的 HTML。 主从结构 当用户在主列表中点击一个英雄时,该组件应该在页面底部显示所选英雄的详情。 在本节,你将监听英雄条目的点击事件,并更新英雄的详情。 添加 click 事件绑定 再往 <li> 元素上插入一句点击事件的绑定代码: heroes.component.html <li *ngFor="let hero of heroes" (click)="onSelect(hero)"> 这是 Angular 事件绑定 语法的例子。 click 外面的圆括号会让 Angular 监听这个 <li> 元素的 click 事件。 当用户点击 <li> 时,Angular 就会执行表达式 onSelect(hero)。 onSelect() 是 HeroesComponent 上的一个方法,你很快就要写它。 Angular 会把所点击的 <li> 上的 hero 对象传给它,这个 hero 也就是前面在 *ngFor 表达式中定义的那个。 添加 click 事件处理器 把该组件的 hero 属性改名为 selectedHero,但不要为它赋值。 因为应用刚刚启动时并没有所选英雄。 添加如下 onSelect() 方法,它会把模板中被点击的英雄赋值给组件的 selectedHero 属性。 src/app/heroes/heroes.component.ts selectedHero: Hero; onSelect(hero: Hero): void {   this.selectedHero = hero; } 修改详情模板 该模板引用的仍然是老的 hero 属性,但它已经不存在了。 把 hero 改名为 selectedHero。 heroes.component.html <h2>{{selectedHero.name | uppercase}} Details</h2> <div><span>id: </span>{{selectedHero.id}}</div> <div>   <label>name:     <input [(ngModel)]="selectedHero.name" placeholder="name">   </label> </div> 刷新浏览器,应用挂了。 打开浏览器的开发者工具,它的控制台中显示出如下错误信息: HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined 出现了什么问题? 当应用启动时,selectedHero 是 undefined,设计如此。 但模板中的绑定表达式引用了 selectedHero 的属性(表达式为 {{selectedHero.name}}),这必然会失败,因为你还没选过英雄呢。 现在,从列表中随便点击一个条目。 应用又正常了。 英雄们显示在列表中,并且所点英雄的详情也显示在了页面的下方。 修复 - 使用 *ngIf 来隐藏空白的细节 该组件应该只有当 selectedHero 存在时才显示所选英雄的详情。 把显示英雄详情的 HTML 包裹在一个 <div> 中。 并且为这个 div 添加 Angular 的 *ngIf 指令,把它的值设置为 selectedHero。 不要忘了 ngIf 前面的星号(*),它是该语法中的关键部分。 src/app/heroes/heroes.component.html (*ngIf) <div *ngIf="selectedHero">   <h2>{{selectedHero.name | uppercase}} Details</h2>   <div><span>id: </span>{{selectedHero.id}}</div>   <div>     <label>name:       <input [(ngModel)]="selectedHero.name" placeholder="name">     </label>   </div> </div> 浏览器刷新之后,英雄名字的列表又出现了。 详情部分仍然是空。 点击一个英雄,它的详情就出现了。 这个应用看起来又再次工作正常显示了。 英雄显示在列表中,当你单击英雄的名字的时候,有关你单击英雄的详细信息就显示在页面的底部了。 为什么这样是正常的 当 selectedHero 为 undefined 时,ngIf 从 DOM 中移除了英雄详情。因此也就不用担心 selectedHero 的绑定了。 当用户选择一个英雄时,selectedHero 也就有了值,并且 ngIf 把英雄的详情放回到 DOM 中。 给所选英雄添加样式 所有的 <li> 元素看起来都是一样的,因此很难从列表中识别出所选英雄。 如果用户点击了“Magneta”,这个英雄应该用一个略有不同的背景色显示出来,就像这样: 所选英雄的颜色来自于你前面添加的样式中的 CSS 类 .selected。 所以你只要在用户点击一个 <li> 时把 .selected 类应用到该元素上就可以了。 Angular 的 CSS 类绑定机制让根据条件添加或移除一个 CSS 类变得很容易。 只要把 [class.some-css-class]="some-condition" 添加到你要施加样式的元素上就可以了。 在 HeroesComponent 模板中的 <li> 元素上添加 [class.selected] 绑定,代码如下: heroes.component.html (toggle the…

2019年05月29日 0Comments 1130Browse 0Like Read more
Computer Science

Angular 英雄编辑器

应用程序现在有了基本的标题。 接下来你要创建一个新的组件来显示英雄信息并且把这个组件放到应用程序的外壳里去。 创建英雄组件 使用 Angular CLI 创建一个名为 heroes 的新组件。 ng generate component heroes CLI 创建了一个新的文件夹, src/app/heroes/,并生成了 HeroesComponent 的 4 个文件。 HeroesComponent 的类文件如下: heroes.component.ts import { Component, OnInit } from '@angular/core'; @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit {   constructor() { }   ngOnInit() {   } } 你要从 Angular 核心库中导入  Component  符号,并为组件类加上 @ Component  注解。 @Component 是一个修饰器函数,这个函数为组件指定了 Angular 元数据。 CLI 自动生成了三个元数据属性: selector — 组件的 CSS 元素选择器。 templateUrl — 组件模板文件的位置。 styleUrls — 组件私有 CSS 样式表文件的位置。 CSS 元素选择器 app-heroes 用来在父组件的模板中匹配 HTML 元素的名称,以识别出该组件。 ngOnInit 是一个生命周期钩子(lifecycle hook),Angular 在创建完组件后很快就会调用 ngOnInit。这里是放置初始化逻辑的好地方。 始终要 export 这个组件类,以便于在其它地方(比如 AppModule)导入它。 添加一个 hero 属性 往 HeroesComponent 中添加一个 hero 属性,用来表示一个名叫 “Windstorm” 的英雄。 hero = 'Windstorm'; 显示英雄 打开模板文件 heroes.component.html。删除 Angular CLI 自动生成的默认内容,改为到 hero 属性的数据绑定。 heroes.component.html {{hero}} 显示 HeroesComponent 视图 要显示 HeroesComponent 你必须把它加到壳组件 AppComponent 的模板中。 别忘了,app-heroes 就是 HeroesComponent 的 元素选择器(element selector)。 所以,只要把 <app-heroes> 元素添加到 AppComponent 的模板文件(app.component.html)中就可以了,就放在标题下方。 app.component.html <h1>{{title}}</h1> <app-heroes></app-heroes> 如果 CLI 的 ng serve 命令仍在运行,浏览器就会自动刷新,并且同时显示出应用的标题和英雄的名字。 创建一个 Hero 类 真实的英雄当然不仅仅只有一个名字。 在 src/app 文件夹中为 Hero 类创建一个文件,并添加 id 和 name 属性。 src/app/hero.ts export class Hero {   id: number;   name: string; } 回到 HeroesComponent 类,并且导入这个 Hero 类。 把组件的 hero 属性的类型重构为 Hero。 然后以 1 为 id、以 “Windstorm” 为名字初始化它。 修改后的 HeroesComponent 类应该是这样的: src/app/heroes/heroes.component.ts import {Component, OnInit} from '@angular/core'; import {Hero} from '../hero'; @Component({   selector: 'app-heroes',   templateUrl: './heroes.component.html',   styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit {   hero: Hero = {     id: 1,     name: 'Windstorm'   };   constructor() {   }   ngOnInit() {   } } 页面显示变得不正常了,因为你刚刚把 hero 从字符串改成了对象。 显示 hero 对象 修改模板中的绑定,以显示英雄的名字,并在详情中显示 id 和 name,就像这样: heroes.component.html (HeroesComponent 的模板) <h2>{{hero.name}} Details</h2> <div><span>id: </span>{{hero.id}}</div> <div><span>name: </span>{{hero.name}}</div> 浏览器自动刷新,并显示这位英雄的信息。 使用 UppercasePipe 进行格式化 把 hero.name 的绑定修改成这样: <h2>{{hero.name | uppercase}} Details</h2> 对浏览器进行刷新。现在,你会发现英雄的名字显示成了大写字母。 位于管道操作符( | )的右边的单词 uppercase 表示的是一个插值绑定,用于调用内置的 UppercasePipe。 管道(Pipes) 是格式化字符串、金额、日期和其它显示数据的好办法。 Angular 发布了一些内置管道,当然你还可以创建自己的管道。 编辑英雄 用户应该能在一个 <input> 文本输入框(textbox)中编辑英雄的名字。 当用户输入时,这个输入框应该能同时显示和修改英雄的 name 属性。 也就是说,数据流从组件类流出到屏幕,并且从屏幕流回到组件类。 要想让这种数据流动自动化,就要在表单元素 <input> 和组件的 hero.name 属性之间建立双向数据绑定。 双向绑定 把 HeroesComponent 模板中的英雄详情区重构成这样: src/app/heroes/heroes.component.html (HeroesComponent 模板) <div>   <label>name:     <input [(ngModel)]="hero.name" placeholder="name"/>   </label> </div> [(ngModel)] 是 Angular 的双向数据绑定句法。 这里把 hero.name 属性绑定到了 HTML 的 textbox 元素上,以便数据流可以双向流动:从 hero.name 属性流动到 textbox,并且从 textbox 流回到 hero.name 。 缺少 FormsModule 注意,当你加上 [(ngModel)] 之后这个应用无法工作了。 打开浏览器的开发工具,就会在控制台中看到如下信息: Uncaught Error: Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'. 虽然 ngModel 是一个有效的 Angular 指令,不过它在默认情况下是不可用的。 它属于一个可选模块 FormsModule,你必须自行添加此模块才能使用该指令。 AppModule Angular 需要知道如何把应用程序的各个部分组合到一起,以及该应用需要哪些其它文件和库。 这些信息被称为元数据(metadata)。 最重要的 @NgModule 装饰器位于顶级类 AppModule 上。 Angular CLI 在创建项目的时候就在 src/app/app.module.ts 中生成了一个 AppModule 类。 这里也就是你要添加 FormsModule 的地方。 导入 FormsModule 打开 AppModule (app.module.ts) 并从 @angular/forms 库中导入 FormsModule 符号。 app.module.ts (FormsModule 符号导入) import {FormsModule} from '@angular/forms'; 然后把 FormsModule 添加到 @NgModule 元数据的 imports 数组中,这里是该应用所需外部模块的列表。 app.module.ts(@NgModule 导入) imports: [   BrowserModule,   FormsModule ], 刷新浏览器,应用又能正常工作了。你可以编辑英雄的名字,并且会看到这个改动立刻体现在这个输入框上方的 <h2> 中。 声明 HeroesComponent 每个组件都必须声明在(且只能声明在)一个 NgModule 中。 你没有声明过 HeroesComponent,可为什么应用却正常工作呢? 这是因为 Angular CLI 在生成 HeroesComponent 组件的时候就自动把它加到了 AppModule 中。 打开 src/app/app.module.ts 你可以在顶部找到 HeroesComponent 已经被导入过了。 src/app/app.module.ts import {HeroesComponent} from './heroes/heroes.component'; HeroesComponent 也已经声明在了 @NgModule.declarations 数组中。 declarations: [   AppComponent,   HeroesComponent ], 注意:AppModule 声明了应用中的所有组件,AppComponent 和 HeroesComponent。 最终代码预览 应用跑起来应该是这样的:在线例子 / 下载范例。…

2019年05月24日 0Comments 1351Browse 0Like Read more
1…164165166167168…237
Archives
  • June 2026
  • May 2026
  • April 2026
  • March 2026
  • February 2026
  • January 2026
  • December 2025
  • November 2025
  • October 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019
  • June 2019
  • May 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
Categories
  • Computer Science (2,367)
    • Confluence (663)
    • Gradle (12)
  • U.S. (514)
  • 文化旅游 (146)

COPYRIGHT © 2020 CWIKIUS. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

湘ICP备2020018253号-1