這兩天看了看angular4的文檔,發現他和angular1.X的差異真的是太大了,官方給出的那個管理英雄的Demo是一個很是好的入門項目,這裏給出一個管理我的計劃的小項目,從頭到尾一步一步講解如何去實現他,但願對你有所幫助。這篇文章不會講解如何去用angular4,這部分東西你能夠參考官網,本文講解的是用angular作一個小項目的全過程。寫的比較倉促,疏漏不免,請各位多多指點。css
本項目是angular4.0的一個Demo,能夠實現對我的計劃的管理。目的是分享一下我的作一個angular項目的通常作法,但願能爲一些朋友提供參考。項目參考了vue-tutorial,在此對原做者表示感謝。html
git地址:https://github.com/yibingxiong/ng-plan
博客地址:http://www.cnblogs.com/floor/前端
本開發過程不對angular4.0的使用進行詳細講解,一些基本概念和一些工具的安裝使用請參考官網vue
ng new ng-plan
cd ng-plan
ng serve
爲了簡化樣式編寫,直接用個第三方庫bootstrap,在/src/index.html的heade引入,以下
<link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
git
<nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#"> <i class="glyphicon glyphicon-time"></i> 計劃板 </a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">首頁</a></li> <li><a href="#">計劃列表</a></li> </ul> </div> </div> </nav> <div class="container"> <div class="col-sm-3"> <div class="panel panel-default"> <div class="panel-heading"> <h1 class="text-center">已有時長</h1> </div> <div class="panel-body"> <h1 class="text-center">1 小時</h1> </div> </div> </div> <div class="col-sm-9"> <div class="jumbotron"> <h1>任務追蹤</h1> <p> <strong> <a href="#">建立一個任務</a> </strong> </p> </div> </div> </div>
效果以下github
從上圖能夠看見使用命令行建立組件,組件會被自動註冊到根模塊中,因此直接使用就能夠了
直接在/src/app/app.component.html最上邊加上bootstrap
<app-navigation></app-navigation>
若是不出現意外的話,你看到的效果應該和2中效果同樣,那爲何要這樣作呢?方便維護,便於複用。在這個小項目你可能並不能看出他的好處,並且本項目將導航作成獨立組件沒有太大意義。架構
import { RouterModule } from '@angular/router';
如今咱們的/src/app/module.ts應該是下邊這個樣子app
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { NavigationComponent } from './navigation/navigation.component'; @NgModule({ declarations: [ AppComponent, NavigationComponent, ], imports: [ BrowserModule, RouterModule.forRoot([ { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: 'home', component: HomeComponent }, ]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
能夠看到imports中作了路由配置,此時運行會出錯,由於尚未Home組件angular4
將/src/app/app.component.html改成以下
<app-navigation></app-navigation> <div class="container"> <div class="col-sm-3"> <div class="panel panel-default"> <div class="panel-heading"> <h1 class="text-center">已有時長</h1> </div> <div class="panel-body"> <h1 class="text-center">1 小時</h1> </div> </div> </div> <div class="col-sm-9"> <router-outlet></router-outlet> </div> </div>
能夠發現一部份內容被替換爲<router-outlet></router-outlet>
這樣,路由匹配的內容將會在這裏顯示。
上邊發現咱們home找不到,如今建立這個組件,與上邊建立navigation是相似的
直接運行
ng g component home
angular-cli會幫咱們作好一切
運行效果以下
下面修改咱們的Home組件,更改他的html文件以下
<div class="jumbotron"> <h1>任務追蹤</h1> <p> <strong> <a>建立一個任務</a> </strong> </p> </div>
效果以下
發現和前面的效果基本同樣了,不過不要着急,咱們慢慢來!
這其實仍是建立一個組件,因此咱們仍是用命令行來搞!
ng g component plan-list
{ path: 'planlist', component: PlanListComponent },
沒毛病!
<div class="time-entries"> <div class="list-group"> <a class="list-group-item"> <div class="row"> <div class="col-sm-2 user-details"> <img src="http://pic.dfhon.com/pictures/20100401/141048.jpg" class="avatar img-circle img-responsive" /> <p class="text-center"> <strong> 大熊 </strong> </p> </div> <div class="col-sm-2 text-center time-block"> <h3 class="list-group-item-text total-time"> <i class="glyphicon glyphicon-time"></i> 1 </h3> <p class="label label-primary text-center"> <i class="glyphicon glyphicon-calendar"></i> 2017-08-04 </p> </div> <div class="col-sm-7 comment-section"> 必定要完成 </div> <div class="col-sm-1"> <button class="btn btn-xs btn-danger delete-button"> X </button> </div> </div> </a> <a class="list-group-item"> <div class="row"> <div class="col-sm-2 user-details"> <img src="http://pic.dfhon.com/pictures/20100401/141048.jpg" class="avatar img-circle img-responsive" /> <p class="text-center"> <strong> 大熊 </strong> </p> </div> <div class="col-sm-2 text-center time-block"> <h3 class="list-group-item-text total-time"> <i class="glyphicon glyphicon-time"></i> 1 </h3> <p class="label label-primary text-center"> <i class="glyphicon glyphicon-calendar"></i> 2017-08-04 </p> </div> <div class="col-sm-7 comment-section"> 必定要完成 </div> <div class="col-sm-1"> <button class="btn btn-xs btn-danger delete-button"> X </button> </div> </div> </a> </div> </div>
.avatar { height: 75px; margin: 0 auto; margin-top: 10px; margin-bottom: 10px; } .user-details { background-color: #f5f5f5; border-right: 1px solid #ddd; margin: -10px 0; } .time-block { padding: 10px; } .comment-section { padding: 20px; }
查看效果
目前咱們的導航還不能點擊,下面解決這個問題,修改/src/app/navigation/navigation.component.html
<nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" routerLink="/" routerLinkActive="active"> <i class="glyphicon glyphicon-time"></i> 計劃板 </a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li routerLinkActive="active"><a routerLink="/home">首頁</a></li> <li routerLinkActive="active"><a routerLink="/planlist" >計劃列表</a></li> </ul> </div> </div> </nav>
這樣你就能夠在首頁和計劃列表點來點去了。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-plan-list', templateUrl: './plan-list.component.html', styleUrls: ['./plan-list.component.css'] }) export class PlanListComponent implements OnInit { plans = [ { name: '大熊', date: '2017-8-8', totalTime: 1, comment: '學習到天亮' }, { name: '大熊', date: '2017-8-8', totalTime: 1, comment: '學習到天亮' }, { name: '大熊', date: '2017-8-8', totalTime: 1, comment: '學習到天亮' } ]; constructor() { } ngOnInit() { } }
<div class="time-entries"> <div class="list-group"> <a class="list-group-item" *ngFor="let plan of plans"> <div class="row"> <div class="col-sm-2 user-details"> <img src="http://pic.dfhon.com/pictures/20100401/141048.jpg" class="avatar img-circle img-responsive" /> <p class="text-center"> <strong> {{plan.name}} </strong> </p> </div> <div class="col-sm-2 text-center time-block"> <h3 class="list-group-item-text total-time"> <i class="glyphicon glyphicon-time"></i> {{plan.totalTime}} </h3> <p class="label label-primary text-center"> <i class="glyphicon glyphicon-calendar"></i> {{plan.date}} </p> </div> <div class="col-sm-7 comment-section"> {{plan.comment}} </div> <div class="col-sm-1"> <button class="btn btn-xs btn-danger delete-button"> X </button> </div> </div> </a> </div> </div>
import { Injectable } from '@angular/core'; import { Plan } from '../bean/plan'; @Injectable() export class PlanService { plans: Plan[]; constructor() { this.plans = [ { id: 11, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }, { id: 22, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }, { id: 33, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }]; } getPlans() { return this.plans; } addPlan(newplan: Plan) { this.plans.push(newplan); } deletePlan(id: number) { let index = 0; for (let i = 0; i < this.plans.length; i++) { if (this.plans[i].id === id) { index = i; break; } } this.plans.splice(index, 1); } getPlan(id: number) { for (let i = 0; i < this.plans.length; i++) { if (this.plans[i].id === id) { return this.plans[i]; } } } }
import { PlanService } from './service/plan.service';
providers: [PlanService],
import { Component, OnInit } from '@angular/core'; import { PlanService } from '../service/plan.service'; import { Plan } from '../bean/plan'; @Component({ selector: 'app-plan-list', templateUrl: './plan-list.component.html', styleUrls: ['./plan-list.component.css'] }) export class PlanListComponent implements OnInit { plans: Plan[]; constructor(private planService: PlanService) { } ngOnInit() { this.plans = this.planService.getPlans(); } }
能夠看到,我將原來寫死在這個組件的plans去掉了,而是去調用了一個服務獲取我所須要的數據。至此,你所看到的效果與原來的無異,可是咱們的項目又向前買進了一大步。
下面看一下如何刪除一個計劃,這裏主要用到的是事件的綁定。
// 刪除計劃 deletePlan (plan) { this.planService.deletePlan(plan.id); this.plans = this.planService.getPlans(); }
一樣的數據在前端的顯示可能要求不一樣,這時須要咱們對數據進行一些格式化,管道這種東西是你的首選。
觀察文件變化和app.module的變化
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'dataFormat' }) export class DataFormatPipe implements PipeTransform { transform(value: number): String { const d = new Date(); d.setTime(value); const year = d.getFullYear(); const month = d.getMonth() + 1; const date = d.getDate(); const h = d.getHours(); const m = d.getMinutes(); const s = d.getSeconds(); return (year + '-' + (month < 10 ? ('0' + month) : month) + '-' + (date < 10 ? ('0' + date) : date) + ' ' + (h < 10 ? ('0' + h) : h) + ':' + (m < 10 ? ('0' + m) : m) + ':' + (s < 10 ? ('0' + s) : s)); } }
在app.component中使用
可是會法現一個問題,當刪除計劃時總時長沒有響應變化,下面設法解決這個問題。
通過一番堅苦卓絕的尋找,我終於在https://scotch.io/tutorials/get-angular-1-features-in-angular-2#toc-global-communication-with-services 找到了一個比較簡單的解決方法,雖然我也不是太理解這個方法,不過能用。下面將我作的修改的文件列出來供你參考。此問題的解決還能夠用一個些數據狀態庫。
// /home/yibingxiong/ng-plan/src/app/service/plan.service.ts import { Injectable } from '@angular/core'; import { Plan } from '../bean/plan'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; @Injectable() export class PlanService { plans: Plan[]; totalTime = 0; totalTime$ = new BehaviorSubject<number>(this.totalTime); constructor() { this.plans = [ { id: 11, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }, { id: 22, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }, { id: 33, name: '大熊', date: 100000, totalTime: 1, comment: '學習到天亮' }]; this.totalTime = this.getTotalTime2(); } getPlans() { return this.plans; } // 添加計劃 addPlan(newplan: Plan) { this.totalTime = this.getTotalTime2(); this.updateTotalTimeSbj(this.totalTime); this.plans.push(newplan); } // 刪除計劃 deletePlan(id: number) { let index = 0; for (let i = 0; i < this.plans.length; i++) { if (this.plans[i].id === id) { index = i; break; } } this.plans.splice(index, 1); this.totalTime = this.getTotalTime2(); this.updateTotalTimeSbj(this.totalTime); } // 得到一個計劃 getPlan(id: number) { for (let i = 0; i < this.plans.length; i++) { if (this.plans[i].id === id) { return this.plans[i]; } } } // 計算計劃總時間 getTotalTime2() { let t = 0; for (const p of this.plans) { t += p.totalTime; } return t; } get getTotalTime(): number { return this.totalTime; } private updateTotalTimeSbj(value) { this.totalTime$.next(value); } }
// /home/yibingxiong/ng-plan/src/app/app.component.ts import { Component } from '@angular/core'; import { PlanService } from './service/plan.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(private planService: PlanService) { } title = 'app'; }
// /home/yibingxiong/ng-plan/src/app/app.component.html <app-navigation></app-navigation> <div class="container"> <div class="col-sm-3"> <div class="panel panel-default"> <div class="panel-heading"> <h1 class="text-center">已有時長</h1> </div> <div class="panel-body"> <h1 class="text-center">{{planService.getTotalTime}} 小時</h1> </div> </div> </div> <div class="col-sm-9"> <router-outlet></router-outlet> </div> </div>
{ path: 'create', component: CreateComponent },
<a routerLink="/create">建立一個任務</a>
<div class="form-horizontal"> <div class="form-group"> <div class="col-sm-6"> <label>日期</label> <input type="date" class="form-control" placeholder="Date" /> </div> <div class="col-sm-6"> <label>時間</label> <input type="number" class="form-control" placeholder="Hours" /> </div> </div> <div class="form-group"> <div class="col-sm-12"> <label>備註</label> <input type="text" class="form-control" placeholder="Comment" /> </div> </div> <button class="btn btn-primary">保存</button> <a class="btn btn-danger">取消</a> <hr> </div>
<div class="form-horizontal"> <div class="form-group"> <div class="col-sm-6"> <label>日期</label> <input type="date" class="form-control" placeholder="Date" [(ngModel)]="newplan.date" /> </div> <div class="col-sm-6"> <label>時間</label> <input type="number" class="form-control" placeholder="Hours" [(ngModel)]="newplan.totalTime" /> </div> </div> <div class="form-group"> <div class="col-sm-12"> <label>備註</label> <input type="text" class="form-control" placeholder="Comment" [(ngModel)]="newplan.comment" /> </div> </div> <button class="btn btn-primary" (click)="addPlan(newplan)">保存</button> <a class="btn btn-danger">取消</a> <hr> </div>
<div class="form-horizontal"> <div class="form-group"> <div class="col-sm-6"> <label>日期</label> <input type="date" class="form-control" placeholder="Date" [(ngModel)]="newplan.date" /> </div> <div class="col-sm-6"> <label>時間</label> <input type="number" class="form-control" placeholder="Hours" [(ngModel)]="newplan.totalTime" /> </div> </div> <div class="form-group"> <div class="col-sm-12"> <label>備註</label> <input type="text" class="form-control" placeholder="Comment" [(ngModel)]="newplan.comment" /> </div> </div> <button class="btn btn-primary" (click)="addPlan(newplan)">保存</button> <a class="btn btn-danger">取消</a> <hr> </div>
<a class="btn btn-danger" (click)="cancel()">取消</a>
修改planService,移除假數據
在planlist中加入無數據判斷
本文是我學習angular4兩個晚上作的一個小Demo,我是一邊作項目一邊寫的這個文檔,因此按照個人文檔操做通常能夠順利完成項目,可是不免有一些疏漏,請自行查找問題所在。
本項目雖小,可是他將angular的一些和性要點都用到了。
本項目的結構僅供參考,你能夠搭建更加清晰的項目結構。例如將頁面組件都放到page目錄,將一些碎片化的組件放到components目錄,這都是能夠的,你能夠靈活運用。很是感謝你能如此耐性的看到這裏,但願本文能對你有所幫助。 最後,要是你以爲這篇文章還不錯,請在個人博客http://www.cnblogs.com/floor/ 點個關注,或者點個推薦。或者幫忙點一下star,github地址:https://github.com/yibingxiong/ng-plan