angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)

前端之家收集整理的这篇文章主要介绍了angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

返回目录

使用 NG ZORRO

上一篇文章中,我们已经安装了NG ZORRO,并在跟模块中引入了,在子模块中使用还需要再次引入。

编辑layout模块中的header组件

在layout.module.ts中引入NG ZORRO

  1. import { NgZorroAntdModule } from 'ng-zorro-antd';
  2.  
  3. imports: [
  4. CommonModule,RouterModule,NgZorroAntdModule
  5. ],

编辑header.component.html简单布局

  1. <div class="header">
  2. <div class="logo">
  3. <img src="../../../assets/img/logo.png"/>
  4. </div>
  5. <div class="top-menu">
  6. <ul nz-menu [nzMode]="'horizontal'" style="line-height: 64px;">
  7. <li nz-menu-item><i class="anticon anticon-home"></i> 主页</li>
  8. <li nz-menu-item routerLink="blog"><i class="anticon anticon-appstore"></i> 博客</li>
  9. <li nz-submenu>
  10. <span title><i class="anticon anticon-setting"></i> 秘密</span>
  11. <ul>
  12. <li nz-menu-item>秘密1 </li>
  13. <li nz-menu-item>秘密2 </li>
  14. </ul>
  15. </li>
  16. <li nz-menu-item><i class="anticon anticon-user"></i>神马</li>
  17. <li nz-menu-item><i class="anticon anticon-mail"></i></li>
  18. </ul>
  19. </div>
  20. </div>

在header.component.css中简单调整下样式

  1. .logo {
  2. width: 120px;
  3. height: 66px;
  4. margin-left: 50px;
  5. float: left;
  6. }
  7. .logo img{
  8. height: 100%;
  9. width: auto;
  10. }
  11. .top-menu{
  12. float: right;
  13. margin-right: 50px;
  14. }
  15. .header{
  16. height: 66px;
  17. border-bottom: 1px solid #e9e9e9;
  18. }

看看效果展开二级菜单的时候报错了,说我们要包含"BrowserAnimationsModule" 或者"NoopAnimationsModule"模块

在app.module.ts中引用

  1. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
  2.  
  3. imports: [
  4. RouterModule,BrowserModule,NgZorroAntdModule.forRoot(),RoutesModule,BrowserAnimationsModule
  5. ],

简单编辑下footer组件

  1. <div class="footer">
  2. 易兒善©2017
  3. </div>
  1. .footer{
  2. background-color: darkgray;
  3. padding: 20px 50px;
  4. width: 100%;
  5. text-align: center;
  6. }

创建服务

要和后台交互,我们就需要有http请求,需要用到angular的http模块。从angular2到现在的angular5http模块也有些变化。
我是这样设计的,把api请求封装成一个基类,然后在此基础上封装一个针对后台apb框架的基类,最后才是我们应用所需要的api请求数据组件。

api-base-service.ts

  1. import { HttpClient,HttpHeaders,HttpParams } from '@angular/common/http';
  2. import { Observable } from 'rxjs/Observable';
  3. import 'rxjs/add/operator/do';
  4. import 'rxjs/add/operator/catch';
  5. import * as moment from 'moment';
  6. import { environment } from '../../../environments/environment';
  7.  
  8. /**
  9. * 封装HttpClient,主要解决
  10. * + 优化HttpClient在参数上便利性
  11. * + 统一实现 loading
  12. * + 统一处理时间格式问题
  13. */
  14. export abstract class ApiBaseService {
  15. constructor(protected http: HttpClient) { }
  16.  
  17. private _loading = false;
  18.  
  19. /** 是否正在加载中 */
  20. get loading(): boolean {
  21. return this._loading;
  22. }
  23.  
  24. parseParams(params: any): HttpParams {
  25. let ret = new HttpParams();
  26. if (params) {
  27. // tslint:disable-next-line:forin
  28. for (const key in params) {
  29. let _data = params[key];
  30. // 将时间转化为:时间戳 (秒)
  31. if (moment.isDate(_data)) {
  32. _data = moment(_data).unix();
  33. }
  34. ret = ret.set(key,_data);
  35. }
  36. }
  37. return ret;
  38. }
  39.  
  40. private begin() {
  41. console.time('http');
  42. this._loading = true;
  43. }
  44.  
  45. private end() {
  46. console.timeEnd();
  47. this._loading = false;
  48. }
  49.  
  50. /** 服务端URL地址 */
  51. get SERVER_URL(): string {
  52. return environment.SERVER_URL;
  53. }
  54.  
  55. /**
  56. * GET请求
  57. *
  58. * @param {string} url URL地址
  59. * @param {*} [params] 请求参数
  60. */
  61. get(url: string,params?: any): Observable<any> {
  62. this.begin();
  63. return this.http
  64. .get(url,{
  65. params: this.parseParams(params)
  66. })
  67. .do(() => this.end())
  68. .catch((res) => {
  69. this.end();
  70. return res;
  71. });
  72. }
  73.  
  74. /**
  75. * POST请求
  76. *
  77. * @param {string} url URL地址
  78. * @param {*} [body] body内容
  79. * @param {*} [params] 请求参数
  80. */
  81. post(url: string,body?: any,params?: any): Observable<any> {
  82. this.begin();
  83. return this.http
  84. .post(url,body || null,{
  85. params: this.parseParams(params)
  86. })
  87. .do(() => this.end())
  88. .catch((res) => {
  89. this.end();
  90. return res;
  91. });
  92. }

abp-api-service.ts

  1. import {ApiBaseService} from "./api-base-service"
  2. import { HttpClient } from '@angular/common/http';
  3. import { Observable } from 'rxjs/Observable';
  4.  
  5.  
  6. /**
  7. * 进一步封装HttpClient,主要解决
  8. * 后台apb框架返回数据的解析
  9. */
  10. export abstract class AbpApiService extends ApiBaseService {
  11. constructor(protected http: HttpClient) {
  12. super(http);
  13. }
  14.  
  15. abpGet<T>(url: string,params ? : any): Observable<any> {
  16. return this.get(url,params).map(r=>{
  17. return this.process<T>(r);
  18. });
  19. }
  20. abpPost<T>(url: string,params?: any): Observable<any> {
  21. return this.post(url,body,params).map(r=>{
  22. return this.process<T>(r);
  23. })
  24. }
  25. private process<T>(r:any):any{
  26. const data = r as Result;
  27. if(data.success){
  28. return data.result as T;
  29. }else {
  30. console.error(data.error);
  31. throw data.error;
  32. }
  33. }
  34. }
  35.  
  36. // 后台返回的结构体
  37. export class Result{
  38. success:boolean;
  39. error:any;
  40. result:any;
  41. }

  1. import { Injectable } from '@angular/core';
  2. import {HttpClient} from '@angular/common/http';
  3. import {Observable} from 'rxjs/Observable';
  4. import 'rxjs/add/operator/map';
  5. import 'rxjs/add/observable/of';
  6. import {AbpApiService} from "../../core/services/abp-api-service"
  7. import {environment} from "../../../environments/environment"
  8.  
  9. const blogApiUrl ={
  10. getNoteList :environment.SERVER_URL+"/api/services/app/NoteServer/GetPreNoteList",getNote:environment.SERVER_URL+"/api/services/app/NoteServer/GetNote",like:environment.SERVER_URL+"/api/services/app/NoteServer/Like"
  11. };
  12. // 要使该服务可以依赖注入,需要加上下面这个标签,并且在模块中声明
  13. @Injectable()
  14. export class BlogService extends AbpApiService{
  15.  
  16. constructor(protected http: HttpClient) {
  17. super(http)
  18. }
  19.  
  20. public GetNoteList(params:GetNoteDto):Observable<PagedData<PreNoteDto>> {
  21. const url = blogApiUrl.getNoteList;
  22. return this.abpGet<PagedData<PreNoteDto>>(url,params);
  23. }
  24.  
  25. public GetNote(id:number):Observable<PreNoteDto>{
  26. const url = blogApiUrl.getNoteList+"?Id="+id;
  27. return this.abpGet<PreNoteDto>(url);
  28. }
  29.  
  30. public Like(id:number):void{
  31. const url = blogApiUrl.getNoteList;
  32. this.abpPost(url,null,{id:id})
  33. }
  34. }
  35. export class GetNoteDto{
  36. SkipCount = 0;
  37. MaxResultCount = 10;
  38. key = '';
  39. }
  40. export class PreNoteDto{
  41. id:number;
  42. title:string;
  43. creationTime:string;
  44. like:number;
  45. collect:number;
  46. scan:number;
  47. isPublic:boolean;
  48. content:string;
  49. }
  50. // 分页数据类
  51. export class PagedData<T>{
  52. items:T[];
  53. totalCount:number;
  54. }

blog.module.ts中声明

  1. import {BlogService} from "./blog.service";
  2.  
  3.  
  4. providers: [ BlogService ],

博客模块列表组件

我打算这样实现列表,上面一个大的搜索框,下面就是列表,不用分页,使用加载更多的方式。
注意这个子模块我们要使用NG ZORRO,所以还是要在子模块中引入。后面这些和样式调整就不再写详细的内容

布局note-list.component.html

  1. <div class="content">
  2. <div class="serch-content">
  3. <nz-input [nzType]="'search'" [(ngModel)]="key" [nzPlaceHolder]="'输入你想知道的'" style="height: 38px;"></nz-input>
  4. </div>
  5. <div>
  6. <div *ngFor="let note of preNoteList" class="note-list">
  7. <div class="note-title">
  8. <h1> <a (click)="linkTo(note.id)">{{note.title}}</a> </h1>
  9. <em>{{note.creationTime}}</em>
  10. </div>
  11. <article [innerHTML]="note.content"></article>
  12. <div class="note-btn">
  13. <div>
  14. <i class="anticon anticon-eye"></i>{{note.scan}}
  15. <i class="anticon anticon-heart"></i> {{note.like}}
  16. </div>
  17. </div>
  18. </div>
  19. </div>
  20. <div *ngIf="loadMore" class="load-more" (click)="getNoteList()" >
  21. <span>点击加载更多</span><i class="anticon anticon-arrow-down"></i>
  22. </div>
  23. <div *ngIf="loading" class="load-more">
  24. <nz-spin></nz-spin>
  25. </div>
  26. </div>

note-list.component.ts

  1. import { Component,OnInit } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. import marked from 'marked';
  4. import {BlogService,PreNoteDto,GetNoteDto} from "../blog.service"
  5.  
  6. @Component({
  7. selector: 'app-note-list',templateUrl: './note-list.component.html',styleUrls: ['./note-list.component.css']
  8. })
  9. export class NoteListComponent implements OnInit {
  10. preNoteList:PreNoteDto[]=[];
  11. loadMore = false;
  12. loading =false;
  13. key="";
  14.  
  15. constructor(private router: Router,private blogService :BlogService
  16. ) { }
  17.  
  18. ngOnInit() {
  19. this.getNoteList();
  20. }
  21. getNoteList(f=false){
  22. this.loading= true;
  23. if(f)this.preNoteList =[];
  24. const param = new GetNoteDto();
  25. param.key = this.key;
  26. param.SkipCount = this.preNoteList.length;
  27. this.blogService.GetNoteList(param).do(()=>{
  28. this.loading = false;
  29. }).subscribe(m=> {
  30. this.loadMore = m.totalCount>this.preNoteList.length;
  31. m.items.forEach((v,i)=>{
  32. v.content = marked(v.content);
  33. this.preNoteList.push(v);
  34. });
  35. });
  36. }
  37. linkTo(id:number){
  38. this.router.navigate(['blog/note',id]);
  39. }
  40.  
  41. }

博客文章显示

布局 note.component.html

  1. <div class="content">
  2. <div class="note-title">
  3. <h1> {{note.title}} </h1>
  4. <div class="note-btn">
  5. <div>
  6. <em>{{note.creationTime}}</em>
  7. <i class="anticon anticon-eye"></i>{{note.scan}}
  8. <i class="anticon anticon-heart"></i> {{note.like}}
  9. </div>
  10. </div>
  11. </div>
  12. <article [innerHTML]="note.content"></article>
  13. <div *ngIf="loading" class="load">
  14. <nz-spin></nz-spin>
  15. </div>
  16. <div style="margin: auto;padding: 50px 10px;">
  17. <div class="like" [ngClass]="{'liked':_like}" (click)="ILike()">
  18. <i class="anticon anticon-heart-o"></i>喜欢 | {{note.like}}
  19. </div>
  20. </div>
  21. </div>
  1. import { Component,OnInit } from '@angular/core';
  2. import { ActivatedRoute } from '@angular/router'; // 路由
  3. import {BlogService,PreNoteDto} from "../blog.service"
  4. import marked from 'marked';
  5.  
  6. @Component({
  7. selector: 'app-note',templateUrl: './note.component.html',styleUrls: ['./note.component.css']
  8. })
  9. export class NoteComponent implements OnInit {
  10.  
  11. _like=false;
  12. note= new PreNoteDto();
  13. loading=true;
  14. constructor(private route: ActivatedRoute,private server:BlogService
  15. ) { }
  16.  
  17. ngOnInit() {
  18. // 获取路由传值
  19. this.route.params.subscribe((params) => {
  20. const id = params.id;
  21. this.server.GetNote(id).subscribe(r=>{
  22. r.content = marked(r.content);
  23. this.note = r;
  24. },r=>{
  25. console.error(r);
  26. },()=>{
  27. this.loading= false;
  28. })
  29. });
  30. }
  31. ILike(){
  32. this._like = !this._like;
  33. if(this._like){
  34. this.note.like++;
  35. this.server.Like(this.note.id);
  36. }else {
  37. this.note.like--;
  38. this.server.UnLike(this.note.id);
  39. }
  40. }
  41.  
  42. }

先简单实现,后面再慢慢优化吧

源码下载

思考

angular模块,组件,普通的ts文件之间的关系和区别。动态路由是如何传值的页面样式和布局如何优化

猜你在找的Angularjs相关文章