ionic是一個用來快速開發跨平台應用的架構,亮點不少:
- 學習成本低
- 對前端開發者來說,學習成本不是很高,如果有接觸過angular,就幾乎沒有什麼學習成本了
- 簡單易用
- 強大的CLI,
->start
->platform
->serve
->build
->emulate
,全套服務指令行完成,不用寫配置檔案,不用F5run
- 元件多而強大
- 提供了很多強大的現成元件,很容易實作流行的互動效果,比如下拉重新整理(
)、上拉加載/瀑布流(ion-refresher
)、tabs(ion-infinite-scroll
)、側邊欄菜單(ion-tabs
)等等,隻需要寫一點點代碼,就能實作這些流行效果,比native開發速度快太多了ion-side-menu
- 支援cordova插件
- 打開了這扇門,意味着我們可以使用大量的原生功能,比如調用相機拍照、響應傳回按鈕、打電話發短信發郵件……都隻要幾行代碼就能搞定
- 更新速度快
- 已經是v1.2.4了,快速更新意味着有人維護,bug能被迅速修複
當然,也有缺陷,否則就沒有這篇筆記了,如下:
- 新版本不完全向後相容
- 不相容沒關系,給個詳細文檔說明下也行啊,沒有
- bug難以定位
- angular+cordova+ionic+javascript,發現問題後,很難确定是哪塊的問題
- 性能優化難
- 動畫卡頓,低端機體驗更差,而優化措施一般都是建議少用動畫少用陰影少用漸變……但是,不用實在太醜,而且與native應用體驗差太多
- 其它
- 奇奇怪怪的問題找不到答案,大半夜的翻stackoverflow……
一.jsonp跨域,php服務怎麼寫
P.S.這是angular的問題,當時沒整理筆記,後來就忘記了遇到過這麼個問題
angular的$http可以發送jsonp請求,用法類似于jQuery,如下:
// 請求資料
$http.jsonp(sUrl).success(function(res){
// ...
}).error(function(err){
// ...
});
sUrl
有特殊要求,必須帶上
callback
參數,而且參數值隻能是
JSON_CALLBACK
,angular文檔:
Relative or absolute URL specifying the destination of the request. The name of the callback should be the string JSON_CALLBACK.
例如:
而問題是:php服務怎麼寫?直接傳回用
JSON_CALLBACK()
包裹的json資料?
不對,因為真正請求的url中
callback !== JSON_CALLBACK
,被angular偷偷(文檔沒有說明)替換掉了,是以背景需要這樣寫:
<?php
if (strpos($_SERVER["REQUEST_URI"], 'callback')) {
$res = json_encode($res);
// echo $_SERVER["REQUEST_URI"];
// /angular/test/http/main.php?callback=angular.callbacks._0
// $res = 'JSON_CALLBACK('.$res.')';
// 錯的
$res = $_GET['callback'].'('.$res.')';
}
?>
當然,這是get的情況,比較簡單,如果是post,還需要通過别的方式取
callback
,完整例子如下:
<?php
// get
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$res = '{';
// arg
if (isset($_GET['arg'])) {
$res .= '"arg": "'.$_GET['arg'].'", ';
}
// method
if (strpos($_SERVER["REQUEST_URI"], 'callback')) {
// echo $_SERVER["REQUEST_URI"];
// /angular/test/http/main.php?callback=angular.callbacks._0
$res .= '"arg": "'.$_GET['arg'].'", ';
$res .= '"method": "jsonp"}';
// $res = 'JSON_CALLBACK('.$res.')';
// 錯的
$res = $_GET['callback'].'('.$res.')';
}
else {
$res .= '"method": "get"}';
}
echo $res;
}
// post
else if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 直接拿拿不到,因為傳過來的是json串
// echo $_POST['arg'];
$jsonArg = file_get_contents('php://input');
if (isset($jsonArg)) {
echo substr($jsonArg, 0, strlen($jsonArg) - 1).', "method": "post"}';
}
else {
echo '{"method": "post"}';
}
}
?>
二.ion-content的阻尼回彈效果沒了
ionic v1.2取消了
ion-content
預設的阻尼回彈效果,明明一模一樣的代碼,就是沒有回彈效果,後來發現是版本更新的鍋,翻了很久後,在官方部落格的評論裡找到了答案:
Great news, thank you! It seems that the “has-bouncing=’true'” does not work with the native scroll, is it correct? I managed though to have it again by going to back go js scroll (overflow-scroll=”false”)
I only checked in the browser so if any one can confirm that with native scrolling removes bouncing that would be great.
I need this feature for a custom ‘pull refresh’ method I had.
也就是說,v1.2之後想要有阻尼回彈效果,需要這麼做:
三.多個view之間的資料共享
也就是多個controller之間的資料共享(一般不同view對應不同controller)問題,當然,最簡單的方法是用全局變量(
$rootScope
),但這樣不好,更合理的方式是自己寫個
service
或者
factory
,提供資料存取接口,在需要的地方依賴注入即可,比如:
.service('DataServ', ['$http', 'UIServ', function($http, UIServ) {
// ...
// 字典
var oDir = {
// key: value
};
function save(val) {
var sKey = Date.now() + '';
oDir[sKey] = val;
return sKey;
}
function get(sKey) {
return oDir[sKey];
}
return {
// ...
save: save,
get: get
};
}]);
然後通過url傳遞
sKey
即可實作資料共享,很幹淨
四.通知視圖更新
在模闆中寫好了資料展示,但如果打開頁面後資料還沒到,模闆解析完了,由于沒有資料顯示空白頁,過了一會兒資料到了,發現視圖沒有更新,仍然是一片空白,比如:
<!-- html -->
<p ng-cloak>{{data}}</p>
// js
app.controller('MainCtrl', ['$scope', 'DataServ', function($scope, DataServ) {
// ...
setTimeout(function() {
// ...
$scope.data = 'data';
})
}]);
因為給data指派的操作跑到了controller作用域外,此時需要手動通知視圖更新,如下:
// ...
$scope.data = 'data';
$scope.$apply();
當然,一般不需要手動通知,即便是異步傳回的資料,因為這裡隻與作用域有關,總之,如果發現視圖需要手動更新,添上
$apply
就好了
五.php原生xml擴充如何擷取裡的内容
rss格式中會有
<content: encoded>
标簽,直接取
content
取不到,需要特殊的方式:
$content = (string)$item->children("content", true);
// $encodedContent = $content->encoded;
// $content->encoded傳回轉義過的html,比如把&轉成&,一般用于<pre>直接展示
當然,前提是使用原生xml擴充(
$xml = simplexml_load_file($url);
)解析xml才會遇到這個問題,更多用法請檢視php – How to parse CDATA HTML-content of XML using SimpleXML? – Stack Overflow
六.在浏覽器中打開外部頁面
需要使用一個cordova插件,cd進項目檔案夾,然後:
安裝完成後就可以調用了,不用修改配置檔案,不用引入其他js,如下:
// openInBrowser
window.open(‘http://example.com’, ‘_system’); Loads in the system browser
window.open(‘http://example.com’, ‘_blank’); Loads in the InAppBrowser
window.open(‘http://example.com’, ‘_blank’, ‘location=no’); Loads in the InAppBrowser with no location bar
window.open(‘http://example.com’, ‘_self’); Loads in the Cordova web view
// test
window.open(url, '_system'); // 系統預設浏覽器
// window.open(url, '_blank'); // 很醜的安卓内置浏覽器
// window.open(url, '_self'); // 同上
一般都用 _system ,另外兩個實在太醜,更多内容請檢視Cordova InAppBrowser Plugin Example using ionic framework
最近新發現 修改後的浏覽器插件,可以用圖檔自定義部分樣式
github位址:https://github.com/initialxy/cordova-plugin-themeablebrowser
cordova plugin add cordova-plugin-themeablebrowser
七.splash screen黑屏白屏
P.S.黑屏白屏其實是同一個問題,但這個問題相當難解決,筆者花了快1天才搞定
ionic預設內建了
splashscreen
插件,這個cordova插件效果不是很完美,預設配置隻在首次打開app時顯示splash screen,但實際效果是:
When the app starts the splash screen shows for a few seconds as expected, and then the screen goes black for @1 second and then white for @2 seconds and then the main app page appears.
Is there any way to prevent the black and white pages appearing? I read somewhere that a black page appears when there is no splash page but I do have a splash page and it appears fine.
在stackoverflow找到了這個問題描述,簡直太貼切了,但是單靠問題下面的回答無法解決白屏問題,還需要改配置檔案
最初發現的現象是黑屏(把上面英文描述裡的white換成黑),後來找到了原因:主視圖容器
ion-nav-view
是空的,而它的背景色是
#000
,是以修複方法是給裡面塞個
ion-view
:
<!-- 内容 -->
<ion-nav-view>
<!-- 防止啟動時黑屏 -->
<ion-view></ion-view>
</ion-nav-view>
或者添css,把
ion-nav-view
的背景色改成白色。但問題還沒解決,黑屏問題變成白屏問題了,解決方案比較麻煩
-
把splashscreen插件降級到v2.0.0
v2.0.0之後的版本有bug,目前(2016/1/9)自帶的版本是v3.0.0。先cd到項目檔案夾,然後指令行:
// 删掉現有版本 cordova plugin rm cordova-plugin-inappbrowser // 安裝v2.0.0 cordova plugin add cordova-plugin-inappbrowser
-
改配置檔案MyApp/config.xml
<preference name="SplashScreen" value="screen"/> <preference name="AutoHideSplashScreen" value="false"/> <preference name="auto-hide-splash-screen" value="false"/> <preference name="ShowSplashScreenSpinner" value="false"/> <preference name="SplashMaintainAspectRatio" value="true" /> <preference name="SplashShowOnlyFirstTime" value="false"/> <preference name="SplashScreenDelay" value="10000"/>
取消自動隐藏(改為代碼控制隐藏),把持續時間改為較大的值(10秒),設定每次打開應用都顯示splash screen
P.S.預設隻有
SplashScreen
和
SplashScreenDelay
,需要把其它的(
SplashMaintainAspectRatio
可選)都添上
-
改app.js
手動隐藏splash screen,在run裡面添上
.run(['$rootScope', function($rootScope) { // init // $rootScope.isLoading = false; // hide splash immediately if(navigator && navigator.splashscreen) { navigator.splashscreen.hide(); } }); }])
這樣就好了,不要延時調用hide,否則仍然會出現白屏(有些解決方案要求$timeout 50毫秒hide,仍然會出現白屏,不要這樣做)
最怨念的問題結束了,看似簡單的功能,想要有完美的原生體驗卻很難,奇奇怪怪的問題很難解決,目前可行的解決方案可能過段時間就不行了,可以檢視White page showing after splash screen before app load感受一下
八.安卓版本簽名釋出
八.安卓版本簽名釋出
各種簽名方法都過時了,目前(2016/1/9)可以用的簽名方法如下:
-
在MyApp\platforms\android建立keystore
具體步驟請檢視:Ionic toturial for building a release.apk
-
建立release-signing.properties檔案
具體步驟請檢視:How to automatically sign your Android apk using Ionic framework and Crosswalk
-
build
cd到項目檔案夾,然後指令行
ionic build --release android
,成功後會生成2個東西,在MyApp\platforms\android\build\outputs\apk下,分别是android-armv7-release.apk和android-x86-release.apk,一般平闆和PC用x86,手機用arm7,如果要上傳google play的話,2個都要傳,下載下傳時有自動識别
至于crosswalk,提供了chrome核心,能讓低端機支援高端東西,但會讓apk 變大很多(3.5M->23M),添上crosswalk後,感覺。。。嗯,變卡了,但為了支援低端機使用者,一般都會添上crosswork