Angular2入门系列教程3-多个组件,主从关系
好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系
现在,假设我们要做一个博客,博客的的文章具有主从关系,文章和文章详情;现在,我们新建一个Article的文件夹和其组件的基本架构(顺便说一下,我使用的是vs code 有个Angular2 fiels的插件,可以直接建立)
效果如下
我们需要显示博客,那就要建立一个blogdata的数据来源,这里为了方便我们直接采用本地变量的模式来做;为了保证功能单一性原则,我们新建一个data的文件夹,在里面建立Blog类
export class Blog{ id:number; title:string; } export let BLOGS:Blog[]=[ { id:1,title:"号外号外?奥巴马要下台啦"}, { id:2,title:"什么?奥巴马要下台啦?"}, { id:3,title:"号外号外?川普要上台了"}, { id:4,title:"啥?我大四川人也要当美国总统了?"}, { id:5,title:"mdzz,一群麻瓜,统统查杀"}, { id:6,title:"首推龙文,必须出具"} ]
然后在我们的Article组件中导入它
import { Component } from '@angular/core'; import {BLOGS,Blog} from '../data/blog'; @Component({ selector: 'ngarticle', templateUrl: './article.component.html', styleUrls:['./article.component.css'] }) export class ArticleComponent { blogList:Blog[]; constructor() { this.blogList=BLOGS; } }
由于article是html自带的标签,我们使用ngarticle作为选择器
然后,我们开始编写我们的组件模板 article.component.html
<div class="article"> <ul class="articleList"> <li *ngFor="let blog of blogList"> <a> {{blog.id}}:{{blog.title}} </a> </li> </ul> </div>
接下来是article.component.css
.articleList { list-style: none; } .articleList li { position: relative; width: 100%; font-size:16px; border-bottom: 1px dashed #d9d9d9; box-sizing: border-box; border-radius:2px; } .articleList li > a { position:relative; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 15px 25px; display: block; width: 100%; color:#333; height:100%; } .articleList li > span { position:relative; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 15px 25px; display: block; color:#000; height:100%; background:69aa6f } .articleList li > a:hover { color: #69aa6f; transition: color 0.3s, box-shadow 0.3s; } .articleList li:hover { background: #efefef; }
完成之后,在我们的app.component.html中使用它
<ngarticle></ngarticle>
然后在命令行中进入项目根目录,使用ng serve命令执行,然后我们就得到了一个错误
错误显示我们的ngarticle是一个未知的组件,未知怎么办,注册嘛,所有的Angular组件都要注册(声明)之后才能使用,具体方法如下
打开我们的App.Module.ts,我们像声明AppComponent一样声明我们的ArticleComponent,方法就是在declaration中添加我们的组件,这个declaration数组就是我们的组件声明的地方,所有的组件都需要在这里声明之后才可以使用
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { ArticleComponent } from './article/article.component'; @NgModule({ declarations: [ AppComponent, ArticleComponent ], imports: [ BrowserModule, FormsModule, HttpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
到此,效果如下
然后我们需要一个显示明细的东西,我们来做个显示明细编辑吧
新建一个article-detail组件,和上边一样,文件夹
articledetail.component.ts
import { Component, OnInit,Input } from '@angular/core'; import {BLOGS,Blog} from '../data/blog'; @Component({ selector: 'article-detail', templateUrl: './articledetail.component.html', styleUrls:['./articledetail.component.css'] }) export class ArticledetailComponent implements OnInit { @Input() blog:Blog; ngOnInit() { } }
这里我们注意到多了一个@Input()装饰器,这个是用来接受组件输入的,待会儿我们修改article.component.html的时候你就知道是干什么的了
articledetail.component.html
<div class="articledetail" *ngIf="blog"> <h2>文章明细</h2> <div class="content"> <div class="row"> <span >ID</span> <span>{{blog.id}}</span> </div> <div class="row"> <span >Title</span> <input type="text" class="myInput" [(ngModel)]="blog.title"/> </div> </div> </div>
这里用了*ngIf 值为blog,表示如果blog有值,为真,那么就显示内容,否则不显示
我们注意到这里又多了一个[(ngModel)],简单就理解为input一类标签的值绑定,双向的哦
articledetail.component.css
.articledetail { margin:20px; width: 100%; margin: 0 auto; } h2{ text-align: center; } .row{ width: 100%; padding: 10px 20px; } .row>span{ margin-left: 25px; } .myInput{ height: 36px; line-height: 36px; border: 0px; border-bottom: 2px solid #000; padding: 6px 12px; box-shadow: 0px 5px 10px #ccc; width: auto; }
因为加入了detail组件,我们先到app.module.ts中注册(声明)下,代码我就不贴了,大家都会了
然后是修改刚才的article组件
article.component.ts
import { Component } from '@angular/core'; import {BLOGS,Blog} from '../data/blog'; @Component({ selector: 'ngarticle', templateUrl: './article.component.html', styleUrls:['./article.component.css'] }) export class ArticleComponent { blogList:Blog[]; selectedBlog:Blog; constructor() { this.blogList=BLOGS; } selectBlog(blog:Blog) { this.selectedBlog=blog; } }
然后是article.component.html
<div class="article"> <ul class="articleList"> <li *ngFor="let blog of blogList" (click)="selectBlog(blog)"> <a> {{blog.id}}:{{blog.title}} </a> </li> </ul> <div> <article-detail [blog]="selectedBlog"></article-detail> </div> </div>
我们看到article.component.ts中新增了一个属性selectedBlog,多了一个事件 selectBlog;这个事件通过(click)="selectBlog(blog)"绑定到了li标签的点击事件上,没错,Angular的点击事件就是这样么绑定的,然后我们在下方看到了我们的article-detail 组件的标签,里面有个 [blog]="selectedBlog",结合到刚才detail组件的@Input() blog:Blog 属性,我们就明白了,Input故名思议就是输入,可以接收父组件的参数;
这里简单聊一聊[blog]类似的传值,[X]会将值绑定到组件或者单个标签的prototype(非attr)上,比如一个input标签有value 的prototy,我们也可以使用这样的绑定,你可以在article-detail组件中的input试一试,而这种绑定是单向的。由此,我们联想到刚才的[(ngModel)],好吧,其实[()]语法相当于两个语法,一个是[value]值绑定。一个是(input)事件的绑定;可以理解为
[ngModel]="blog.title"+(ngModelChange)="blog.title=$event";这两个事件更原始的模样是[value]="blog.title"+(input)="blog.title=$event.target.value",不过我们不用去关心Angular2帮我们做的这些事情,知道怎么用就行了吧
行文到此,我们该来看下效果了
结束语:到此我们可以完整得编写组件了,也知道了一些组件间的交互模式,嗨,也不知道多说些啥,下一篇文章我们将要了解Angular的服务
更新ing。。。
项目已经放到了gitbub上,地址 https://github.com/SeeSharply/LearnAngular
本文章的提交 https://github.com/SeeSharply/LearnAngular/tree/a877676846b22b6dbe5430d02b01d25fb5463c61