前言

Ionic是目前较为流行的Hybird App解决方案,在Ionic开发过程中会遇到很多常见的开发问题,本文尝试对这些问题给出解决方案。


一些常识与技巧

  • list 有延迟,可以在ion-content处使用 overflow-scroll="true"尝试
  • <i>上用ng-click上是没效果的
  • <label>标签内的事件会在整个label内被触发,点哪都触发
  • 快捷修改背景色style="background-color: #212326;"
  • 能用ng-if就用ng-if,ng-if的效率比ng-showng-hide
  • 直接在ion-list中的ion-item中并不能触发ng-click事件,可以在item中的元素上再套一层div
  • 可以用ng-class="{'important': post.important}"配合css 根据列表元素显示不同的效果
  • 获取日期用$filtervar postdate = $filter('date')(date, 'yyyy-MM-dd HH:mm:ss');
  • 列表中的元素不能写成 id : 4,应写成 id : "4",注意在创建id变量的时候也需要转成string,如var id = InfoListService.getListLength()+1+"";
  • 使用$log进行log输出,为什么用$log而不是console.log呢?可以看看这个
  • 在安卓上的体验比较差,动画有延迟?可以试试ionic集成的crosswalk
  • controllersservices 的文件名可能会重合,但是他们意义差不多,可以将controllers中的文件名小写,对应的services中的文件名大写进行区分,或者加后缀xxxControler,xxxService
  • 安装cordova插件的时候用ionic plugin add ...的方式添加,这样会在package.json中添加这个插件的条目,如果有人clone了你的项目想在本地运行,可以用ionic state restore它会根据cordovaPlugins条目安装对应的插件。如果直接用cordova plugin add 安装则不会更新package.json
  • 上传base64编码的时候如果提示413错误,是因为文件过大导致的,可以在nodejs中设置bodyparser的文件限制:

    1
    2
    3
    var bodyParser = require('body-parser');
    app.use(bodyParser.json({limit: '50mb'}));
    app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
  • img 中 base64编码的图片无法显示?在源码中发现angular添加了unsafe标签?需要在白名单中添加data:image

    1
    $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|content|file|assets-library):|data:image\//);
  • 有时候pm2运行有问题,重启一下即可

  • 在ios设备上运行ionic run ios --device

问题列表

  1. 如何在某个界面中去掉导航栏?
  2. 如何在ionic中加载本地图片?
  3. 如何在ionic中嵌入网页代码?
  4. 如何将template加载到某个tab或某个sidemenu项目下?
  5. 运行serve命令时ionic报错?
  6. 用docker跑ionic的时候,不能把地址绑定到0.0.0.0怎么处理?
  7. 加载页面的时候会看到双括号一闪而过?
  8. 更新了数据,如何让界面更新呢?
  9. 如何实现IonicView中card上面有一列分割线的效果?
  10. controller.js和service.js文件越来越大怎么办?
  11. 如何寻找优秀的范例代码?
  12. 如何显示相对时间?
  13. 发布应用的时候如果遇到翻译错误即MissingTranslation怎么办?
  14. 如何在列表右下方添加时间等信息?
  15. 如何回到上一页面?
  16. 如何关闭应用?
  17. 在安卓设备上如何让title居中?
  18. 如何让在sidemenu中的headerbar能够显示头像等其他信息?
  19. ionic的subheader挡住了内容区域怎么办?
  20. 对于需要添加数据的list,在添加数据后页面不能及时刷新造成卡顿怎么办?
  21. ionic如何处理回退按钮?例如询问用户是否真的要退出应用
  22. ionic如何实现对每个请求都添加认证信息或认证失败自动重新登录?
  23. ionic如何实现搜索框内的全部清除按钮?

如何在某个界面中去掉导航栏?

如果某个界面上不想要导航栏,可以简单地在最顶端的标签中添加hide-nav-bar="true"


如何在ionic中加载本地图片?

对于css文件夹中的样式文件中如果要调用本地的图片的话,从该css文件所在的文件夹开始算,例如www/css/style.css要加../,否则在浏览器中可以正常显示,在设备上不行,结构如下所示:

1
2
3
4
5
.login-page {
background:url(../img/signup_bg.png);
background-size: cover;
background-repeat: no-repeat;
}

但是对于在页面中定义的图片路径,从www路径开始算,否则浏览器中可显示,但设备上不行,img文件夹和index.html在一级,如:

1
<img src="img/commander.jpg">


如何在ionic中嵌入网页代码?

使用ng-bind-html这个类,不过它会过滤原始html的标签,我们可以引入$sce模块,用$sce.trustAsHtml()方法信任我们获取的网页


如何将template加载到某个tab或某个sidemenu项目下?

<ion-nav-view name="menuContent"> 可以指定name,然后在子状态中使用该name,ionic就知道该把该状态的template渲染到哪边了。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// signup page
.state('auth.signup', {
url: '/signup',
views: {
'auth-signup': {
templateUrl: 'templates/auth-signup.html',
controller: 'SignUpCtrl'
}
}
})
另有一个tabs中声明该auth-signup:
<ion-tab title="Sign Up" icon-on="ion-ios-personadd"
icon-off="ion-ios-personadd-outline" href="#/auth/signup">
<ion-nav-view name="auth-signup"></ion-nav-view>
</ion-tab>

运行serve命令时ionic报错?

1
ionic $ An uncaught exception occured and has been reported to Ionic

看看你是不还有一个终端在运行着serve呢?


用docker跑ionic的时候,不能把地址绑定到0.0.0.0怎么处理?

可以用ionic serve -all的方法解决


加载页面的时候会看到双括号一闪而过?

angularjs 在使用双括号的时候,第一个加载的页面,也就是应用中的index.html,其未被渲染好的模版可能会被用户看到。用ng-bind就不会遇到这个问题。造成这种现象的原因是,浏览器需要首先加载HTML页面,渲染它,然后Angular才有机会把它解释成你期望看到的内容。不过好消息是,在大多数的模版中你依然可以使用双括号.但是对于index.html页面中的数据绑定操作,建议使用ng-bind

ng-bind使用方式如下: <p ng-bind="greeting"></p>


更新了数据,如何让界面更新呢?

可以用广播,注意$broadcast 和 $emit的区别


如何实现IonicView中card上面有一列分割线的效果?

在css里定义

1
2
3
#info-up {
border-top: 4px solid #f06336;
}


controller.js和service.js文件越来越大怎么办?

所有的控制器不必都放在controllers.js这一个文件中,可以新建controllers文件夹,
然后把每个controller都建一个.js文件,同理services和utils等都是.但注意要在index.html中head部分声明.但是为了避免他们相互覆盖,第一个加载的js中模块中要加[…],其他都不需要。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// File : /js/directives/mainDirective.js
angular.module('app.directives',[]);
// File : /js/directives/myGreatDirective.js
angular.module('app.directives')
.directive('myGreatDirective', function(){
return {
//...
}
});
// File : /js/directives/myBetterDirective.js
angular.module('app.directives')
.directive('myBetterDirective', function(){
return {
//...
}
});
...

angularjs-code-organization了解更多,嗯这篇文章写的还不是best practice,因为你还得记着自己把[]写到那个模块里了,统一地写在app.js中即可,在app.js最下面加上类似:

1
2
angular.module('fcws.controllers',['ionic', 'fcws.services']);
angular.module('fcws.services', []);

可以达到和上面一样的效果,而且可以统一管理.


如何寻找优秀的范例代码?

目前有些ionic 的app没有进行代码混淆,至少ionic官方的ionic view没有进行代码混淆,下载他们的app,文件名改成zip,解压,所有的 www文件都在assets文件夹中,相当于开源了有木有,看看那些最优秀的practice。看中哪些优秀的app,下下来,如何在googleplay上下载?把googleplay应用的地址贴到apps.evozi中。


如何显示相对时间?

如几分钟前,几天前等,可以用momentjs,看这篇教程


发布应用的时候如果遇到翻译错误即MissingTranslation怎么办?

暂时的解决方法是,不进行翻译校正, 在 /platforms/android/build.gradle 中的android {}节中加入:

1
2
3
4
lintOptions {
disable 'MissingTranslation'
disable 'ExtraTranslation'
}


如何在列表右下方添加时间等信息?

span 可以用来将时间之类的附加信息显示到列表右边,如下面会将创建时间显示在name的右边:

1
2
3
4
5
6
<ion-item class="item item-avatar-left " ng-repeat="message in messages">
<img src="../../img/commander.jpg">
<span class="item-note">{{message.create_at}}</span>
<h2 >{{message.name}}</h2>
<p > {{message.content}}</p>
</ion-item >


如何回到上一页面?

$ionicHistory这个模块,引入该模块后使用goBack([backCount]),backCount指定回去多少个页面(-1代表回去一个页面),默认为-1


如何关闭应用?

1
ionic.Platform.exitApp();

在安卓设备上如何让title居中?

在headerbar中添加align-title="center",如:

1
2
3
<ion-header-bar class="bar-positive" align-title="center">
<h1 class="title">{{username}}</h1>
</ion-header-bar>

不过这个设置对ion-view无效,亲测,如果要统一让所有navbar上的title居中(包括上面的headerbar),可以在config里设置,如:

1
2
3
.config(function($stateProvider, $urlRouterProvider,$ionicConfigProvider) {
$ionicConfigProvider.navBar.alignTitle('center');
...

如果要让某一个view title居中,可以用$ionicNavBarDelegate,参考ionic官方文档


如何让在sidemenu中的headerbar能够显示头像等其他信息?

解决方案是去掉headerbar,添加一个avatar到sidemenu content中,如:

1
2
3
4
5
6
7
8
9
10
<ion-side-menu side="left">
<ion-content class="bar-positive">
<ion-list>
<ion-item class="item item-avatar item-positive" href="#">
<img src="img/commander.jpg">
<h2 class=" light">
<i class="icon ion-ios-star"></i>{{title}}
</h2>
<a>{{username}}</a>
</ion-item>


ionic的subheader挡住了内容区域怎么办?

解决方案是给<ion-content>加类has-subheader,同理也可以加has-header。如下:

1
<ion-content class="has-header has-subheader">

对于需要添加数据的list,在添加数据后页面不能及时刷新造成卡顿怎么办?

可以使用$ionicScrollDelegate.resize();在添加数据后手动进行重新刷新,记得添加依赖


ionic如何处理回退按钮?例如询问用户是否真的要退出应用

可以在app.js的.run方法中增加对硬件回退按钮的注册处理,这里我在大部分页面都想注册该事件,除去有二级历史页面的我单独判断了下,注意增加依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ionicPlatform.registerBackButtonAction(function(e) {
var current_state_name = $state.current.name;
if(current_state_name !== 'sidemenu.post'
&& current_state_name !== 'sidemenu.contact_town' &&
current_state_name !== 'sidemenu.contact_people'){
$ionicPopup.confirm({
title: '退出应用',
template: '您确定要退出xxxx吗?'
}).then(function (res) {
if (res) {
//ionic.Platform.exitApp();
navigator.app.exitApp();
} else {
console.log('You are not sure');
}
});
e.preventDefault();
return false;
}else{
navigator.app.backHistory();
}
},100);


ionic如何实现对每个请求都添加认证信息或认证失败自动重新登录?

在应用的注册或者登录部分,不记名token响应了这个请求并且这个token被存储到本地存储中。当你向后端请求一个服务时,你需要把这个token放在头部中。你可以在app.js.config方法中使用AngularJS的拦截器实现这个。每次请求都会被拦截并且会把认证头部和值放到头部中,同理如果服务器端响应401403,跳转到重新登录页面.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$httpProvider.interceptors.push(function ($q, $location, User, $rootScope) {
return {
'request': function (config) {
config.headers = config.headers || {};
if (User.getToken()) {
config.headers.Authorization = 'Bearer ' + User.getToken();
}
return config;
},
'responseError': function (response) {
if (response.status === 401 || response.status === 403) {
//如果之前登陆过
if (User.getToken()) {
$rootScope.$broadcast('unAuthenticed');
}
}
return $q.reject(response);
}
};
});


ionic如何实现搜索框内的全部清除按钮?

在label中的input不能嵌入按钮,因为ionic对于label中的tap事件会进行重定向到input上。解决方案是将label替换成span或div。如下面的搜索框,注意ng-model需要是一个对象才能置空,变量不行:

1
2
3
4
5
6
<span class="item-input-wrapper">
<i class="icon ion-ios-search placeholder-icon"></i>
<input type="search" placeholder="请输入姓名前缀" ng-model="search.key">
<i class="icon ion-close-circled placeholder-icon" style="vertical-align: middle;"
on-tap="clearSearch()" ng-if="search.key.length"></i>
</span>