ONE:
这篇文章会整理一级页面数据的展示以及数据铺设,项目页面的搭建简单布局,还有angular4中的HTTP请求的简单封装,接口数据来源于一个开源教学项目的网络接口.
HttpClient是已有Angular HTTP API的推演,他在一个单独存在的@angular/common/http包中.这是为了确保现有的代码库可以后续慢慢的迁移到新的API中,现在大多数前端应用都需要通过HTTP协议与后端服务器进行通讯.现代浏览器支持使用两种不同的API发起HTTP请求:XMLHttpRequest接口和fetch()API.@angular/common/http中的HttpClient类,Angular为应用程序提供了一个简化的API来实现HTTP功能.它基于浏览器提供的XMLHttpRequest接口.HttpClient带来的其它有点包括:可测试性 强类型的请求和响应对象 发起请求与接收响应时的拦截器支持,以及更好的基于可观察(Observable)对象的错误处理机制;
其实讲了上面扯了那么多也没啥卵子用,只知道Observable是请求后返回的Object对象,能够防止数据频繁请求遗留的问题,例如频繁请求在取消,在没有后台相应的情况下就完成了这样的请求A取消A在请求B的这样的操作,而使用Observable就能够解决这样的问题(当然怎么具体解决的原理我也不明白,人家官网咋说我就咋信了),我下面也仅仅就是把数据请求下来展示到App页面中而已,至于其他部分的功能例如POST的新建/PUT的修改/DELETE的删除/HttpInterceptor拦截器/进度查询等全部的使用介绍,网上的博客你能看懂的就能看懂,看不懂的你就一点也看不懂,完全就是官网翻译下来的东西.有时间的话在之后的博客里面我会详细的总结关于Angular4 Http 网络请求的所有功能代码,下面就不涉及太多.
TWO:
1.从上一篇的博客中我们已经初始化新建了一个新的项目了,然后三个默认的页面分别是 Home,About和Contact,然后我们在新建一个页面随意起名字,让它变成4个Tab的页面(强迫症啊单数就不舒服)新建页面的功能需要使用终端命令啊不要直接鼠标右键新建了会很麻烦的,命令如下:
(新建页面选择pages啊然后起个名字在回车就好了..)
2.然后到pages/tabs/tabs.html页面添加代码:
(1)命名随意但最好符合命名规范,相当于就是一个html与ts绑定到桥梁啊
(2)tab的显示名字啊
(3)tabIcon是图标的名字,图标不是本地图片拖到项目中的,而是从官网查找对应的你要找的图标名,看图吧:
3.然后到tabs.ts文件和app.module.ts中绑定页面:
虽然觉得挺low的,但是就入门来说的话还是提一下吧...以上是新建页面或文件的流程.
THREE:
下面要在home页面展示请求的数据,首先就需要简单封装一个Http网路请求的功能类,我们起名为rest,(注意的是使用命令-ionic g 回车后选择的是provider,然后在起名回车就会生成一个rest用来做网络请求功能的帮助类)之后我们要在不同页面需要做网络请求的时候就直接引用该类调用里面封装好的方法就好啦.
1.创建rest网络封装类:
2.在全局app.module.ts中引入Http的包:
3.嗯终于能写代码了:
import {
Observable }
from
'rxjs/Rx';
import {
Injectable }
from
'@angular/core';
import {
Http,
Response }
from
'@angular/http';
import
'rxjs/add/operator/map';
import
'rxjs/add/operator/catch';
@
Injectable()
export
class
RestProvider {
//feed
private
apiUrlFeeds =
'https://imoocqa.gugujiankong.com/api/feeds/get';
constructor(
public
http:
Http) {
//console.log('Hello RestProvider Provider');
}
/**
* 请求首页的 feeds 流
*
*
@returns
{Observable<string[]>}
*
@memberof
RestProvider
*/
getFeeds():
Observable<
string[]> {
return
this.
getUrlReturn(
this.
apiUrlFeeds);
}
/**
* 全局获取 HTTP 请求的方法
* @sq
*
@private
*
@param
{string}
url
*
@returns
{Observable<string[]>}
*
@memberof
RestProvider
*/
private
getUrlReturn(
url:
string):
Observable<
string[]> {
return
this.
http.
get(
url)
.
map(
this.
extractData)
.
catch(
this.
handleError);
}
/**
* 处理接口返回的数据,处理成 json 格式
* @sq
*
@private
*
@param
{Response}
res
*
@returns
*
@memberof
RestProvider
*/
private
extractData(
res:
Response) {
let
body =
res.
json();
return
JSON.
parse(
body) || {};
}
/**
* 处理请求中的错误,考虑了各种情况的错误处理并在 console 中显示 error
* @sq
*
@private
*
@param
{(Response | any)}
error
*
@returns
*
@memberof
RestProvider
*/
private
handleError(
error:
Response |
any) {
let
errMsg:
string;
if (
error
instanceof
Response) {
const
body =
error.
json() ||
'';
const
err =
body.
error ||
JSON.
stringify(
body);
errMsg =
`
${
error.
status
}
-
${
error.
statusText ||
''
}
${
err
}
`;
}
else {
errMsg =
error.
message ?
error.
message :
error.
toString();
}
console.
error(
errMsg);
return
Observable.
throw(
errMsg);
}
}
这里是对angular http的get请求进行封装,对于其他的用法还没有太深入的理解,打算好好学习了解后,在总结一篇详细的网络请求的文章(吐槽:我学个app端的东西 结果又要学angular 又要学js/ts 还要学HTML/CSS/SCSS 感觉还不如去学swift/android,或是RN呢,每个App混合开发的框架感觉都在吹嘘自己的好处,而忽略不提自己的劣势,而程序员们选择的标准也仅仅是哪个框架有一定语言基础和经验而已,感觉并不在意底层的兼容 代码维护的成本以及APP运行效率等更多的为客户打算的东西,我觉得不应该是这样... ... 所以我打算把ionic3学完在去学习下RN/MUI的使用.我觉得在小城市里面的APP端大多都是外包项目中的一小环节,只是作为辅助,开发成本都要降到最低最快,所以可能这也是这种混合开发框架能火起来的主要原因吧?)
4.添加一个供全局使用的工具类:baseui.ts文件,放到一个新建的文件夹内,封装个showLoading和showToast的方法:
import {
Loading,
LoadingController,
ToastController,
Toast }
from
'ionic-angular';
/**
* UI 层的所有公用方法的抽象类
*
*
@export
*
@abstract
*
@class
BaseUI
*/
export
abstract
class
BaseUI {
constructor() { }
/**
* 通用的展示 loading 的组件
*
*
@protected
*
@param
{LoadingController}
loadingCtrl
*
@param
{string}
message
*
@returns
{Loading}
*
@memberof
BaseUI
*/
protected
showLoading(
loadingCtrl:
LoadingController,
message:
string):
Loading {
let
loader =
loadingCtrl.
create({
content:
message,
dismissOnPageChange:
true
//页面变化的时候自动关闭 loading
});
loader.
present();
return
loader;
}
/**
* 通用的展示 toast 的组件
*
*
@protected
*
@param
{ToastController}
toastCtrl
*
@param
{string}
message
*
@returns
{Toast}
*
@memberof
BaseUI
*/
protected
showToast(
toastCtrl:
ToastController,
message:
string):
Toast {
let
toast =
toastCtrl.
create({
message:
message,
duration:
3000,
//默认展示的时长
position:
'bottom'
});
toast.
present();
return
toast;
}
}
5.之上是页面编写代码之前的准备了,然后先写home.html页面:
<
ion-header
>
<
ion-toolbar
>
<
ion-searchbar
placeholder=
"显示搜索内容提示"
></
ion-searchbar
>
<
ion-icon
name=
"text"
class=
"top_header_message_icon"
></
ion-icon
>
</
ion-toolbar
>
</
ion-header
>
<
ion-content
>
<
div
class=
"floatMenu"
>
<
ion-grid
>
<!-- ion-row里面的 col-4 代表站位百分比的多少 一共有12个格子 -->
<
ion-row
>
<
ion-col
col-4
text-center
>
<
div
>
<
ion-icon
name=
"create"
></
ion-icon
> 提问
</
div
>
</
ion-col
>
<
ion-col
col-4
text-center
>
<
div
>
<!-- 显示一个小竖杠 分割 -->
<
span
style=
"float:left;color:#dddddd;"
>|
</
span
>
<
ion-icon
name=
"albums"
></
ion-icon
> 回答
<
span
style=
"float:right;color:#dddddd;"
>|
</
span
>
</
div
>
</
ion-col
>
<
ion-col
col-4
text-center
>
<
div
>
<
ion-icon
name=
"share-alt"
></
ion-icon
> 分享
</
div
>
</
ion-col
>
</
ion-row
>
</
ion-grid
>
</
div
>
<!-- 内容循环展示 及绑定数据 -->
<
ion-card *
ngFor=
"let f of feeds"
>
<
ion-item
>
<
ion-avatar
item-start
>
<
img
src=
"{{f.HeadFace}}"
>
</
ion-avatar
>
<
p
>{{f.UserNickName}}回答了该问题
<
ion-icon
class=
"more_button"
name=
"more"
></
ion-icon
>
</
p
>
</
ion-item
>
<
h2
>{{f.ContentTitle}}
</
h2
>
<
ion-card-content
>
<
p
>{{f.ContentSummary}}
</
p
>
</
ion-card-content
>
<
ion-row
>
<
ion-col
col-8
center
text-left
>
<
ion-note
>
{{f.LikeCount}}
赞同
·
{{f.CommentCount}}
评论
·
关注问题
</
ion-note
>
</
ion-col
>
<
ion-col
col-4
></
ion-col
>
</
ion-row
>
</
ion-card
>
</
ion-content
>
6.然后为了使界面更加好看美观一些,在home.scss文件中,定义相关的属性:
page-home {
// 为了让图标显示的好看点
.top_header_message_icon {
float:
left;
font-size:
2em;
min-height:
44px;
color:
#848994;
padding:
9px
5px
9px
5px;
text-align:
center;
}
// 这里是使搜索部分不占满顶部 给图标留下空间
.searchbar {
float:
left;
width:
90%;
}
// 这里的布局使三个按钮排版更舒适
.floatMenu {
width:
100%;
height:
35px;
background-color:
#FFFFFF;
margin-bottom:
5px;
color:
#999999;
font-weight:
bold;
}
// card外层显示效果
.card {
margin:
0;
margin-bottom:
10px;
width:
100%;
box-shadow:
none;
}
// 标题显示效果
.card
h2 {
padding-left:
10px;
font-weight:
bold;
font-size:
1.5rem;
}
// 内容文字显示效果
.card
p {
color:
#464646;
font-size:
1.2rem;
}
// 内容外层显示效果
.card-content {
padding-top:
6px;
padding-left:
10px;
padding-bottom:
2px;
}
// 内容下方 显示的文字效果
.card
.note {
padding-left:
5px;
font-size:
1.1rem;
}
}
(如果你声明一些全局都会要使用到的属性,以免每个页面的scss文件都要引用一遍,可以再theme目录下app引用的主题文件中声明全局属性)
7.然后最后写home.ts文件:
import {
Component }
from
'@angular/core';
import {
NavController,
LoadingController,
ToastController }
from
'ionic-angular';
import {
BaseUI }
from
'../../common/baseui';
import {
RestProvider }
from
'../../providers/rest/rest';
@
Component({
selector:
'page-home',
templateUrl:
'home.html'
})
export
class
HomePage
extends
BaseUI {
// 网络加载后的变量定义
feeds:
string[];
// 网络请求失败后的信息变量定义
errorMessage:
any;
// 构造方法 引用的声明
constructor(
public
navCtrl:
NavController,
public
loadingCtrl:
LoadingController,
public
toastCtrl:
ToastController,
public
rest:
RestProvider) {
super();
}
// 生命周期
ionViewDidLoad() {
this.
getFeeds();
}
getFeeds() {
// 加载框弹出
var
loading =
super.
showLoading(
this.
loadingCtrl,
"加载中...");
// rest内首页请求方法调用
this.
rest.
getFeeds()
.
subscribe(
f
=> {
this.
feeds =
f;
loading.
dismiss();
},
error
=>
this.
errorMessage = <
any>
error);
}
}
(在生命周期中进行加载数据的请求,其他没什么)
8.如果你想要设置app风格/主题,可以再theme包中进行编辑和引用:
(light文件你可以自己定义喜欢的主题,或者进行日夜间模式的切换)
FOUR:
以上的代码完成后,保存项目在运行打包测试就可以了,有时候你粘贴代码到你的工程中会造成编辑器没有识别运行报错的情况,所以你可以把一些添加过代码的页面在保存一遍,或在浏览器里面强制刷新,再或者重新运行ionic serve(啊..好烦啊 有时候保存代码工程会自动在浏览器中编译运行,但是会报错误,你反复检查多遍却没发现什么错误,报错也不会提示究竟哪部分代码是出错的原因,所以你最先要做的不是重新找项目的出错点或debug断点调试,而是先像我上述说的强制刷新浏览器,依次重新保存页面,在或者重新ionic serve启动服务)
运行的效果就是下图所示,你也可以在本地配置tomcat,写一个JSON的接口数据,局域网进行请求你自己的网址路径,我项目中的接口是之前一个教学视频中的公开接口方便展示:
FIVE:
1.如果是一级页面点击item,跳转到二级详情页的情况,就会涉及到带值跳转,简单的写一下,比如说传递的数据是接口返回的当前item的id号,html文件内须这样写:
<!-- 内容循环展示 及绑定数据 -->
<
ion-card *
ngFor=
"let f of feeds" (
click)=
"gotoDetails(f.IdentityId)"
>
2.ts文件就要添加相应的代码:
// 带值跳转
gotoDetails(
questionId) {
this.
navCtrl.
push(
DetailsPage, {
id:
questionId });
}
(这个DetailsPage是自己命令行添加的二级详情页的页面,使用navController的push方法就可以了,不要忘记添加的页面需要在相关页面进行导入import)
3.然后在接收详情页的页面代码:
import {
Component }
from
'@angular/core';
import {
IonicPage,
NavController,
NavParams }
from
'ionic-angular';
@
IonicPage()
@
Component({
selector:
'page-details',
templateUrl:
'details.html',
})
export
class
DetailsPage {
id:
string;
constructor(
public
navCtrl:
NavController,
public
navParams:
NavParams) {
}
ionViewDidLoad() {
this.
id =
this.
navParams.
get(
'id');
console.
log(
"----" +
this.
id +
"----");
}
}
(我们就打印一下log看有没有收到数据就可以了,详细的写法肯定就是收到数据后,进行网址拼接来再次的http请求网络数据,在加载到这个详情页的布局中这样子,就没有必要重复的去写了)
4.之后浏览器运行效果是这样的:
(id号能够从log中读到,然后emmmmmmm..好像也没啥相关要注意的地方了)
SIX:
简单总结一下我觉得angular里面的双向的数据绑定还是很不错的,可以简写很多的代码,嗯...但是之前想使用一点关于引用其他公司产品功能的api,接入的不是很好,很多平台下都不支持使用ionic,有支持的API文档也写的非常的不适合新手入门使用,写的非常的省略简单...我都想上去给他两个脸蛋子,惯你毛病了咋的?写文档的那些人公司没给你们工资啊?写的是什么玩应儿!有的更过分啊直接引用了一个github和论坛的教程链接还是15 16年的...哎...
下一篇可能会介绍ionic的插件下载以及使用的介绍,也或者是其他的一些东西总结,最近很烦很暴躁...我何时才能成为技术大牛啊啊啊...