angular使用NG|angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)
返回目录
使用 NG ZORRO
在上一篇文章中,我们已经安装了NG ZORRO,并在跟模块中引入了,在子模块中使用还需要再次引入。编辑layout模块中的header组件
在layout.module.ts中引入NG ZORRO
import { NgZorroAntdModule } from 'ng-zorro-antd';
imports: [
CommonModule,
RouterModule,
NgZorroAntdModule
],
编辑header.component.html简单布局
文章图片
- 主页
- 博客
-
秘密
- 秘密1
- 秘密2
- 神马
- 约
在header.component.css中简单调整下样式
.logo {
width: 120px;
height: 66px;
margin-left: 50px;
float: left;
}
.logo img{
height: 100%;
width: auto;
}
.top-menu{
float: right;
margin-right: 50px;
}
.header{
height: 66px;
border-bottom: 1px solid #e9e9e9;
}
看看效果展开二级菜单的时候报错了,说我们要包含"BrowserAnimationsModule" 或者"NoopAnimationsModule"模块
文章图片
在app.module.ts中引用
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
imports: [
RouterModule,
BrowserModule,
NgZorroAntdModule.forRoot(),
RoutesModule,
BrowserAnimationsModule
],
文章图片
简单编辑下footer组件
易兒善?2017
.footer{
background-color: darkgray;
padding: 20px 50px;
width: 100%;
text-align: center;
}
创建服务
要和后台交互,我们就需要有http请求,需要用到angular的http模块。从angular2到现在的angular5http模块也有些变化。
我是这样设计的,把api请求封装成一个基类,然后在此基础上封装一个针对后台apb框架的基类,最后才是我们应用所需要的api请求数据组件。
文章图片
api-base-service.ts
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import * as moment from 'moment';
import { environment } from '../../../environments/environment';
/**
* 封装HttpClient,主要解决:
* + 优化HttpClient在参数上便利性
* + 统一实现 loading
* + 统一处理时间格式问题
*/
export abstract class ApiBaseService {
constructor(protected http: HttpClient) { }private _loading = false;
/** 是否正在加载中 */
get loading(): boolean {
return this._loading;
}parseParams(params: any): HttpParams {
let ret = new HttpParams();
if (params) {
// tslint:disable-next-line:forin
for (const key in params) {
let _data = https://www.it610.com/article/params[key];
// 将时间转化为:时间戳 (秒)
if (moment.isDate(_data)) {
_data = moment(_data).unix();
}
ret = ret.set(key, _data);
}
}
return ret;
}private begin() {
console.time('http');
this._loading = true;
}private end() {
console.timeEnd();
this._loading = false;
}/** 服务端URL地址 */
get SERVER_URL(): string {
return environment.SERVER_URL;
}/**
* GET请求
*
* @param {string} url URL地址
* @param {*} [params] 请求参数
*/
get(url: string, params?: any): Observable {
this.begin();
return this.http
.get(url, {
params: this.parseParams(params)
})
.do(() => this.end())
.catch((res) => {
this.end();
return res;
});
}/**
* POST请求
*
* @param {string} url URL地址
* @param {*} [body] body内容
* @param {*} [params] 请求参数
*/
post(url: string, body?: any, params?: any): Observable {
this.begin();
return this.http
.post(url, body || null, {
params: this.parseParams(params)
})
.do(() => this.end())
.catch((res) => {
this.end();
return res;
});
}
abp-api-service.ts
import {ApiBaseService} from "./api-base-service"
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
/**
* 进一步封装HttpClient,主要解决:
* 后台apb框架返回数据的解析
*/
export abstract class AbpApiService extends ApiBaseService {
constructor(protected http: HttpClient) {
super(http);
}abpGet(url: string, params ? : any): Observable {
return this.get(url,params).map(r=>{
return this.process(r);
});
}
abpPost(url: string, body?: any, params?: any): Observable {
return this.post(url,body,params).map(r=>{
return this.process(r);
})
}
private process(r:any):any{
const data = https://www.it610.com/article/r as Result;
if(data.success){
return data.result as T;
}else {
console.error(data.error);
throw data.error;
}
}
}// 后台返回的结构体
exportclass Result{
success:boolean;
error:any;
result:any;
}
文章图片
import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import {AbpApiService} from "../../core/services/abp-api-service"
import {environment} from "../../../environments/environment"const blogApiUrl ={
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"
};
// 要使该服务可以依赖注入,需要加上下面这个标签,并且在模块中声明
@Injectable()
export class BlogService extends AbpApiService{constructor(protected http: HttpClient) {
super(http)
}public GetNoteList(params:GetNoteDto):Observable> {
const url = blogApiUrl.getNoteList;
return this.abpGet>(url,params);
}public GetNote(id:number):Observable{
const url = blogApiUrl.getNoteList+"?Id="+id;
return this.abpGet(url);
}public Like(id:number):void{
const url = blogApiUrl.getNoteList;
this.abpPost(url,null,{id:id})
}
}
export class GetNoteDto{
SkipCount = 0;
MaxResultCount = 10;
key = '';
}
export class PreNoteDto{
id:number;
title:string;
creationTime:string;
like:number;
collect:number;
scan:number;
isPublic:boolean;
content:string;
}
// 分页数据类
export class PagedData{
items:T[];
totalCount:number;
}
blog.module.ts中声明
import {BlogService} from "./blog.service";
providers:[ BlogService ],
博客模块列表组件
我打算这样实现列表,上面一个大的搜索框,下面就是列表,不用分页,使用加载更多的方式。布局note-list.component.html
注意这个子模块我们要使用NG ZORRO,所以还是要在子模块中引入。后面这些和样式调整就不再写详细的内容了
{{note.title}}
{{note.creationTime}}{{note.scan}}
{{note.like}}点击加载更多
note-list.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import marked from 'marked';
import {BlogService, PreNoteDto,GetNoteDto} from "../blog.service"@Component({
selector: 'app-note-list',
templateUrl: './note-list.component.html',
styleUrls: ['./note-list.component.css']
})
export class NoteListComponent implements OnInit {
preNoteList:PreNoteDto[]=[];
loadMore = false;
loading =false;
key="";
constructor(private router: Router,
private blogService :BlogService
) { }ngOnInit() {
this.getNoteList();
}
getNoteList(f=false){
this.loading= true;
if(f)this.preNoteList =[];
const param = new GetNoteDto();
param.key = this.key;
param.SkipCount = this.preNoteList.length;
this.blogService.GetNoteList(param).do(()=>{
this.loading = false;
}).subscribe(m=> {
this.loadMore = m.totalCount>this.preNoteList.length;
m.items.forEach((v,i)=>{
v.content = marked(v.content);
this.preNoteList.push(v);
});
});
}
linkTo(id:number){
this.router.navigate(['blog/note', id]);
}}
文章图片
博客文章显示
布局 note.component.html
{{note.title}} {{note.creationTime}}
{{note.scan}}
{{note.like}} 喜欢 | {{note.like}}
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
// 路由
import {BlogService, PreNoteDto} from "../blog.service"
import marked from 'marked';
@Component({
selector: 'app-note',
templateUrl: './note.component.html',
styleUrls: ['./note.component.css']
})
export class NoteComponent implements OnInit {_like=false;
note= new PreNoteDto();
loading=true;
constructor(private route: ActivatedRoute,
private server:BlogService
) { }ngOnInit() {
// 获取路由传值
this.route.params.subscribe((params) => {
const id = params.id;
this.server.GetNote(id).subscribe(r=>{
r.content = marked(r.content);
this.note = r;
},r=>{
console.error(r);
},
()=>{
this.loading= false;
})
});
}
ILike(){
this._like = !this._like;
if(this._like){
this.note.like++;
this.server.Like(this.note.id);
}else {
this.note.like--;
this.server.UnLike(this.note.id);
}
}}
文章图片
先简单实现,后面再慢慢优化吧
源码下载
思考
【angular使用NG|angular使用NG ZORRO来构建博客展示项目(简单实现展示页面)】angular模块,组件,普通的ts文件之间的关系和区别。
动态路由是如何传值的
页面样式和布局如何优化
推荐阅读
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- iOS中的Block
- Linux下面如何查看tomcat已经使用多少线程
- 使用composer自动加载类文件
- angular2内置管道
- android|android studio中ndk的使用