Angular 基础部分 1.2 创建投票网站

这个demo,分为两个组件,组件1负责输入,组件2负责显示和投票。
两个组件本质上是对模型的修改,组件1负责输入模型数据,组件2通过模型输出显示数据,并且通过引入模型的增减函数,而模型2还需要导入从模型1导入input。

Expanding Application

创建新project ng new xx
导入CSS-framework, [Semantic-UI](http://semantic- ui.com/)
其他类似的有 Zurb Foundation or Twitter Bootstrap

npm install semantic-ui --save
cd semantic/
gulp build

好像不能直接在组件使用
可以使用主题,在app/vendor导入

应用组件构建

组件需要
1,保存目前文章列表
2,上传文章的表格

构建输入页面

在app.component.html中构建html

<form class="ui large form segment"> 
  <h3 class="ui header">Add a Link</h3>

  <div class="field">
    <label for="title">Title:</label> 
    <input name="title">
  </div>
  <div class="field">
    <label for="link">Link:</label>
    <input name="link"> 
  </div>
</form>


添加按钮
点击触发addArticle函数

<button (click)="addArticle()"
    class="ui positive right floated button"> 
  Submit link
</button>

在app.components中定义addArticle函数

export class AppComponent {
    addArticle(title: HTMLInputElement, link: HTMLInputElement): boolean {
        console.log(`Adding article title: ${title.value} and link: ${link.value}`);
        return false;
    }
}

接收两个参数titlelink,需要在template的input中添加对应的变量
用#表示局部变量

<input name="title" #newtitle> 
...
<input name="link" #newlink>
...
<button (click)="addArticle(newtitle, newlink)"
  • 在template, 创建button标签,添加click事件,触发函数a
  • 在component, 定义函数a
  • 回到template, 在button添加所需的函数变量

input数据绑定,#newtitle

<input name="title" #newtitle>
表明input绑定变量 #newtitle#newtitle语法上叫做解析(reslove),
意义是使newtitle变量在这个视图层面可用。
现在 newtitle 是一个对象,代表了这个input DOM元素,类型是HTMLInputElement。
所以可以用newtitle.value输出值。

把事件跟动作绑定 Binding actions to events

<button (click)="addArticle(newtitle, newlink)"
表示在button标签中,当click事件发生时,会触发addArticle函数
addArticle 在组件AppComponent export class中被定义
newtitle,newlink来自于input标签中对应的#newtitle#newtitle解析

动作函数定义

addArticle(title: HTMLInputElement, link: HTMLInputElement): boolean {
    console.log(`Adding article title: ${title.value} and link: ${link.value}`);
    return false;
}

titlelink 是对象(HTMLInputElement类型),而不是等于input的值。
所以输出值必须用,title.value, 比如${title.value}
目前只是打印输出值

目前在浏览器console中,可以输出值。

这里写图片描述

构建输出页面

把输入的值显示出来
ng generate component article
创建一个新component

构建articlecomponent.html页面

目标页面
这里写图片描述

<div class="four wide column center aligned votes"> 
  <div class="ui statistic">
    <div class="value"> 
      {{ votes }}
    </div>
    <div class="label">
      Points 
    </div>
  </div> 
</div>
<div class="twelve wide column">
  <a class="ui large header" href="{{ link }}">
    {{ title }} 
  </a>
  <ul class="ui big horizontal list voters"> 
    <li class="item">
      <a href (click)="voteUp()">
        <i class="arrow up icon"></i>
          upvote 
      </a>
    </li>
    <li class="item">
      <a href (click)="voteDown()">
        <i class="arrow down icon"></i> 
        downvote
      </a>
    </li>   
  </ul>       
</div>

分数在左边,文章信息在右边
先设置左右两个div,左边div占 four wide column,右边 twelve wide column(来自SemanticUI)
设置{{ votes }}{{ title }}{{ href }}数据来于ArticleComponent
同时定义两个click按钮

定义component

export class ArticleComponent implements OnInit {
  @HostBinding('attr.class') cssClass = 'row'; 
  votes: number;
  title: string;
  link: string;

  constructor() {
    this.title = 'Angular 2';
    this.link  = 'http://angular.io';
    this.votes = 10;
  }

  voteUp() {
    this.votes += 1;
  }

  voteDown() {
    this.votes -= 1;
  }

  ngOnInit() {
  }

}

导入了 HostBinding, 宿主绑定shuzhu,保持内部元素继承组件设置。
设置组件内部为 row

AppComponent导入app-article

<div class="ui grid posts">
  <app-article>
  </app-article>
</div>

如果页面没有出现app-article
检查浏览器elements 有没有加载,
如果有,但没有显示,可能是app.module.ts没有注册。 p68

这里写图片描述
注意点击上下按钮,会出现页面重新载入,也就是会到默认值10。
因为JS语言中,click事件会有逐层往上传播,比如div->body->html->document,
所以click事件会传输到所有父组件。浏览器会试图加载空连接。
所以要在voteDown函数设置返回false,就不会重载。

return false;

渲染多个Rowa

增加数据结构,用来保存article

创建article.model.ts

export class Article { 
  title: string; 
  link: string; 
  votes: number;

  constructor(title: string, link: string, votes?: number) { 
    this.title = title;
    this.link = link;
    this.votes = votes || 0;
  } 
}

这是Model-view-Controller中的Model
titlevotes代表每一篇新文章的值
votes为可选,默认为0

现在把model引入到ArticleComponent
import { Article } from './article.model';

在export class中,导入模型article: Article;
this.article = new Article 设立新数据
this.article.votes += 1; 定位模型数据

export class ArticleComponent implements OnInit {
  @HostBinding('attr.class') cssClass = 'row'; 
  article: Article;

  constructor() {
    this.article = new Article(
      'Angular 2',
      'http://angular.io',
      10);
  }

  voteUp() {
    this.article.votes += 1;
    return false;
  }

  voteDown() {
    this.article.votes -= 1;
    return false;
  }

  ngOnInit() {
  }

}

同时需要在template中更改对应的模型位置,
比如{{ votes }} 改为 {{ article.votes }}

目前问题是:voteUpvoteDown通过直接修改Article内部数据破坏了对Article的封装,
打破了迪米特法则(Law of Demeter):
法则基本上说:每一个单元应该尽可能跟其他单元保持独立关系,除非跟它有直接关系的。

所以把voteUpvoteDown移到article模型内部,同时在模型中增加domian函数
然后在组件内部引用

voteDown(): boolean { 
  this.article.voteDown(); 
  return false;
}

为什么需要把voteUp同时放在模型和组件中?
因为每一个class有不同的功能,组件负责view展示,而数据递交放在model。
功能区分,对于项目可以便于维护。

Fat Models, Skinny Controllers

多篇文章

在app.component 中 添加模型 p75
articles: Article[];
指定模型并添加数据

  constructor() {
    this.articles = [
      new Article('Angular 2', 'http://angular.io', 3),
      new Article('Fullstack', 'http://fullstack.io', 2),
      new Article('Angular Homepage', 'http://angular.io', 1),
    ]; 
  }

现在要把app.component数据传递到article.component中
Input 指令传递

class ArticleComponent {
@Input() article: Article; 

现在让AppComponent渲染所有文章,

<div class="ui grid posts">
  <app-article
    *ngFor="let article of articles"
    [article]="article">
  </app-article>
</div>

这里写图片描述

添加文章

在app.component中,p81
写入addArticle方法

  addArticle(title: HTMLInputElement, link: HTMLInputElement): boolean {
    console.log(`Adding article title: ${title.value} and link: ${link.value}`);
    this.articles.push(new Article(title.value, link.value, 0));
    title.value = '';
    link.value = '';
    return false;
  }

1,创建一个文章,根据上传数据
2,增加到Article 模型中
3,清除input区域

加入url p82

根据之前的domain函数,负责把url拆解
在增加到ArtcileComponent的template中即可

分数排列

在app.component中添加排序函数

  sortedArticles(): Article[] {
    return this.articles.sort((a: Article, b: Article) => b.votes - a.votes);  }
  }

在app.component中使用

<div class="ui grid posts">
  <app-article
    *ngFor="let article of sortedArticles()" //用sortedArticles()替代Articles
    [article]="article">
  </app-article>
</div>

部署 Deployment

可分为如下步骤
- 把ts语言转化为js语言,浏览器可读
- 把js文件打包成一个或两个文件
- 上传js,HTML,CSS,和images文件

因为Angular程序本质是HTML文件加载JS语言。

build first app for production

使用ng build
ng build --target=production --base-href '/'
把应用建造成生产环境,默认主页是 /
可以设置为 /ng-book-demo/

会创建一个dist文件夹,里面是整个应用的完整打包

上传服务器

有很多方法,这个demo用的是 now
本质上是把dist文件上传到网络

now快速部署js网站,每次部署一个项目都会得到一个独有的url

cd dist
now

输入email,即可得到输出网址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值