# 原型 我们常常听到程序员在报怨项目经理或是客户,报怨他们往往在产品成型后马上提出近一步的需求。我想说这是非常正常的现象,因为作为项目经理或客户,他们是完全的外行。在与他们进行信息交流时,存在信息差属于非常正常的现象。 而我们要做的,就是把这种信息差尽量降低到最小。程序员是必然离不开电脑的,而一个优秀的程序员是必然离不开纸和笔的。在正式编码前,一定要把脑子带上,使用最小的成本将我们计划完成的产品展示给用户,同时也是展示给自己。 而**手绘原型**则是这个最小的成本。在动手编码前,使用铅笔、橡皮、直尺等绘制原型是非常必要的!假设我们当前手绘原型如下: ![image-20210224185547024](https://img.kancloud.cn/c8/bf/c8bf08847bdfc9521b26e2bc08d94e1b_287x271.png) 接下来,让我们共同实现教师保存功能。 ## 初始化组件 使用shell进入项目`src/app`文件夹: ```bash panjie@panjies-Mac-Pro first-app % cd src/app panjie@panjies-Mac-Pro app % pwd /Users/panjie/github/mengyunzhi/angular11-guild/first-app/src/app panjie@panjies-Mac-Pro app % ``` 接下来执行:`ng generate component add`来生成一个教师添加组件: ```bash panjie@panjies-Mac-Pro first-app % cd src/app panjie@panjies-Mac-Pro app % pwd /Users/panjie/github/mengyunzhi/angular11-guild/first-app/src/app panjie@panjies-Mac-Pro app % ng generate component add ? Would you like to share anonymous usage data about this project with the Angular Team at Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more details and how to change this setting, see http://angular.io/analytics. Yes Thank you for sharing anonymous usage data. Would you change your mind, the following command will disable this feature entirely: ng analytics project off panjie@panjies-Mac-Pro app % CREATE src/app/add/add.component.css (0 bytes) CREATE src/app/add/add.component.html (18 bytes) CREATE src/app/add/add.component.spec.ts (605 bytes) CREATE src/app/add/add.component.ts (263 bytes) UPDATE src/app/app.module.ts (540 bytes) panjie@panjies-Mac-Pro app % ``` > info: 如果出现以下提示(google在问我们是否在共享我们的使用情况),输入`y`后回车键(允许)继续。当然了,你可以直接按回车(不分享我们的数据给google)后继续 。 以上命令将自动为我们创建四个文件、更新一个文件。创建的文件分别为构成组件的三个文件:`src/app/add/add.component.css`, `src/app/add/add.component.html`,`src/app/add/add.component.ts`,一个供快速开发的测试文件`src/app/add/add.component.spec.ts`;更新了当前`src/app`文件夹下的模块文件`src/app/app.module.ts`。 ```bash panjie@panjies-Mac-Pro app % tree . ├── add │   ├── add.component.css ➊ │   ├── add.component.html ➊ │   ├── add.component.spec.ts ➊ │   └── add.component.ts ➊ ├── app ├── app-routing.module.ts ├── app.component.css ├── app.component.html ├── app.component.spec.ts ├── app.component.ts └── app.module.ts ➋ 2 directories, 10 files ``` - ➊ 新建文件 - ➋ 更新文件 `src/app/app.module.ts`更新情况如下: ```typescript import { AddComponent } from './add/add.component'; ➋ @NgModule({ declarations: [ AppComponent, AddComponent ➊ ], ``` ➊将新建的`AddComponent`自动添加到了`AppModule`模块下的`declarations`中, ➋自动添加了相应的文件引用。 ## 测试 接下来我们继续使用`ng t`运行单元测试以查看当前新建的教师添加组件: ````bash panjie@panjies-Mac-Pro first-app % ng t ```` ![image-20210224201001301](https://img.kancloud.cn/8b/a8/8ba8bf74a63f5f2712258d5ede56e6f2_814x302.png) 🧐 什么情况,说好的使用`ng t`显示的组件呢?怎么仍然显示的是教师列表呢?再刷新几次试试: ![image-20210224200926679](https://img.kancloud.cn/20/a9/20a9d66c2d9fdc3e1293cd231bd805f9_542x196.png) 是的,和你看到的一样。angular会随机的显示以前的教师列表组件以及我们刚刚初始化的ADD组件,较以前仅有一个组件比较,angular当前显示的信息中表明正在测试两个组件,被标明了测试的顺序。当我们的Add组件被最后测试时,最终的界面将停留在Add组件,而当我们的Add组件被最先测试时,最终的界面则将停留在教师列表组件。 ![image-20210224201212679](https://img.kancloud.cn/c1/19/c119673e09e1a33e734d1aa9908617f8_482x198.png) 此时,我们可以找到Add组件对应的测试文件`add.component.spec.ts`,将第5行的`describe`变更为`fdescribe`,表示强制(force)执行当前测试同时忽略其它以`describe`声明的测试: ```typescript describe('AddComponent', () => { ✘ fdescribe('AddComponent', () => { ✔ ``` 使用`ctrl(command)+s`保存当前文件后,测试界面将自动更新: ![image-20210224202724554](https://img.kancloud.cn/fe/f7/fef7fdbb4abd8a25f773e47da763072c_443x226.png) 其中绿色代码正在执行的测试,而灰色表示该测试未执行。 ## V层 下面我们打开`add.component.html`: ```html <p>add works!</p> ``` 删除文件中的代码并加入以下代码,以初始化教师添加表单: ```html <form class="container-sm"> <div class="mb-3 row"> <label for="name" class="col-sm-2 col-form-label">姓名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="name"> </div> </div> <div class="mb-3 row"> <label for="username" class="col-sm-2 col-form-label">用户名</label> <div class="col-sm-10"> <input type="text" class="form-control" id="username"> </div> </div> <div class="mb-3 row"> <label for="email" class="col-sm-2 col-form-label">Email</label> <div class="col-sm-10"> <input type="text" class="form-control" id="email"> </div> </div> <div class="mb-3 row"> <label class="col-sm-2 col-form-label">性别</label> <div class="col-sm-10"> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="inlineRadioOptions" id="sex-male" value="option1"> <label class="form-check-label" for="sex-male">男</label> </div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="inlineRadioOptions" id="sex-female" value="option2"> <label class="form-check-label" for="sex-female">女</label> </div> </div> </div> <div class="mb-3 row"> <div class="col-sm-10 offset-2"> <button class="btn btn-primary">保存</button> </div> </div> </form> ``` 最终效果如下: ![image-20210224205636653](https://img.kancloud.cn/79/6b/796b037f04ae6619a93b1005ded63677_994x301.png) # 本节资源 | 名称 | 地址 | | ---------------------- | ------------------------------------------------------------ | | Jasmine fdescribe | [https://jasmine.github.io/api/3.6/global.html#fdescribe](https://jasmine.github.io/api/3.6/global.html#fdescribe) | | CLI 概览与命令参考手册 | [https://angular.cn/cli](https://angular.cn/cli) | | 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step2.3.1.zip](https://github.com/mengyunzhi/angular11-guild/archive/step2.3.1.zip) |