1. 程式人生 > >ionic專案實戰-小白踩坑走起【2017/3/7起·持續更新】

ionic專案實戰-小白踩坑走起【2017/3/7起·持續更新】

幾個月的專案實戰,走在適配安卓與ios的路上浪,總結經驗,相互交流【2017/3/7起·持續更新】

【1】固定
 副標題固定可使用         

<ion-header-bar class="bar bar-subheader"></ion-header-bar> 
同理底部固定使用  ion-footer-bar

元件的頁面固定,不隨頁面滾動:在ion-content之前使用ion-nav-buttons,在標籤裡面就是你需要固定的元件,div或其他,需要使用relative進行定位使用top調節位置。頁面滾動的時候標題欄是不會動的,所以這裡其實就是相對標題欄定位,實現固定

【注意:】這裡需要用ion-nav-bar標籤把它包起來,否則頁面切換的時候上一頁面的元件可能會存在下一頁面中。包起來才能在頁面切換中銷燬掉

<ion-view>
    <ion-nav-bar>
        <ion-nav-buttons>  主要程式碼</ion-nav-buttons>    
    </ion-nav-bar>
   <ion-content>     
   </ion-content>
</ion-view>

【2】頁面的帶參跳轉

一般使用<a href="#/name/{id}"></a>,單一引數,把id或code值傳過去下一個頁面,多引數的時候建議使用$state.go

頁面修改為<a href="" ng-click="go(x.id,x.code,x.name)"></a>   x是資料來源,現需要傳遞3個引數到下一個頁面

          controlers中:$scope.go=function(id,code,name){

                          $state.go('name',{sid:id,scode:code,sname:name})    //controllers記得新增服務$state

                    }

          在app.js中對應配置路徑,在name頁面對應使用$stateParams接受傳遞過來的引數使用

【3】仿新聞網站tab在[上面是滾動條tab,最右端有下拉鍵,點擊出現所有tab標籤,點選面板tab,滾動條自動滾動到對應位置,下面資料也同步重新整理]

一般|難點主要在事件觸發滾動自己滾動,而且滾動條檢視中要有被點選tab

html中:<ion-scroll id="subjectScroll" delegate-handle="small"></ion-scroll> 設定滾動條

controllers.js中  var scrollWith=(document.getElementById("subjectScroll").offsetWidth)/4;  //我是用百分比的,計算每個tab所佔具體畫素

主要觸發函式:

$scope.tabSlide=function(num){  //num是當前點選物件的序號
    	console.log(num);
        var other=typeNum%4;//tab 4分展示多餘數的數量,typeNum是tab的總數
        var session=typeNum/4//tab模組數量,4個為一模組
	    var numLine=typeNum-other+1; //tab的鄰界數,大於等於該數時為多餘數序號
	    var endLine=typeNum-4;
        if(num<4){
        	$ionicScrollDelegate.$getByHandle('small').scrollTo(0);
        }
        else{
        	$ionicScrollDelegate.$getByHandle('small').scrollTo(scrollWith*(num-3));
        }
        
    }
這裡主要是我面板顯示只會有4個,所以先考慮介面tab有多少個對應進行分組。scrollTo不是偏移量,是具體值。當點選小於4,則滾動條自然不用滾動,大於4則對應計算位置,觸發滑動。程式碼不完整,更多是提供思路解決問題

【4】雙向資料繫結設定為空
  初始化$scope.keyword={text:""};

 頁面上使用keyword.text繫結ng-model

 設定為空使用命令$scope.keyword.text="";

【5】分頁引數的使用(上拉載入)、下拉刷

  services.js中

.factory('SeaService', ['$http',  function($http) {
	var seaService = {};
	try
	{
	seaService.getSea = function(Count,no,Word, Type, Token,callback) {//這裡引數對應看介面需要
		$http({
			method: 'POST',
			url: //請求資料地址,
			params: {       //k,t,pno等都是介面的引數名,對應看介面需要的名
				k:Word,
				t:Type,
				pno:no,
				psize:Count,
				token:Token
			}
		}).success(function(response) {
			callback(true, response);
	
		}).error(function() {
			callback(false, '');
		});
	}
}catch(error){
}
	return seaService;

}])

html中【資料渲染部分就不顯示了】

<ion-infinite-scroll ng-if="hasmore" on-infinite="loadMore()" distance="1%"></ion-infinite-scroll>


controllers.js中
.controller('SeaCtrl', ['$scope', 'SearchService', '$stateParams',
function($scope, SearchService, $stateParams,) {
	
	$scope.pSearch = [];//定義空陣列,用於存放所有列表資料渲染頁面
	$scope.hasmore = true;
	var run = false;
	var count = 0;
	var total =0;
	var isLoadMore = false; //是否正在執行上拉
	var t = 1;
        var pageno=0 ;
	var pageCount=10;

    /*判斷是否載入完畢*/
	$scope.hasMoreData = function() {
		var hasMore = pageno * pageCount < total;
		console.log("pageno:" + pageno + "*" + "pageCount:" + pageCount + "----值" + total + " " + hasMore);
		return hasMore;
	};
 
	$scope.loadMore = function() {
       if(total==$scope.pSearch.length){
			$scope.hasmore=false;
			console.log("total的值:"+total);
			$scope.$broadcast('scroll.infiniteScrollComplete');
		}
		isLoadMore = true;
		var old = $scope.pSearch;
		if(old.length != 0) {
			console.log("載入更多資料的入口");
			$scope.initData(3);
		} 
	};

	/* state:1初始化,3載入更多 */
	$scope.initData = function(state) {
		console.log(!run);
		if(!run) {
			run = true;
			if(state == 3) {
				if(!$scope.hasmore) { // 載入完全
					$scope.$broadcast('scroll.infiniteScrollComplete');
					return;
				}
			}
			$scope.getGoodsList(state);

		} else {
			if(state == 3 || state == 1) {
				$scope.$broadcast('scroll.infiniteScrollComplete'); //廣播事件結束
				isLoadMore = false;
			}
		}
	};


	$scope.getGoodsList = function(state) {
	try{
		pageno++;
		SearchService.getSearch(pageCount,pageno,k,t,token,function(isSuccess, response) {
			if(isSuccess) {	
			  try{
				console.log("呼叫函式時候的pageno:"+pageno);
				if(state == 1) {
					console.log("請求拿到了第一次資料");
					$scope.pSearch = response.data.rows;
					console.log(JSON.stringify($scope.pSearch));
		  			total = response.data.total;
                                        $scope.hasmore =$scope.hasMoreData();

					if(response.data.total == 0) {
						$scope.tipRun = true;
					}
					 try{
					  if($scope.pSearch.length == 0) {
						 console.log('第一次請求沒有資料');
					   }
					}catch(err){
						
					}
				} else {
					if(state == 3 && $scope.pSearch.length == 0) {
						$scope.hasmore = false;
						$scope.$broadcast('scroll.infiniteScrollComplete');
					} else {
						for(var i = 0; i < response.data.rows.length; i++) {
							$scope.pSearch.push(response.data.rows[i]);
							++count;
							console.log(count + pageCount);
							if(count +pageCount >= total) {
								$scope.hasmore = false;
								break;
							}
						}
					}
				}
			   }catch(err){
                   console.log("請求不成功:原因可能token失效/網路狀態不佳")
			    }
			} else {
				
			}
			if(isLoadMore) {
				$scope.$broadcast('scroll.infiniteScrollComplete'); //廣播事件結束
					isLoadMore = false;
				}
			run = false;
			}
);
	}catch(error){
	alert("controller中商品搜尋呼叫函式失敗:"+error);
}
		};
	
      $scope.initData(1);//進入頁面直接載入初始資料

	}

])
【1】下拉載入功能呢個標籤的顯示依賴ng-if=“hasmore”,hasmore為true的時候向上拉就會觸發函式,為false時標籤消失上拉載入功能自然消失。

【2】在controllers.js中最後一行可以看到呼叫initData(1)這個函式,一進入頁面就會自然呼叫這個函式,,而且是優先,但是這裡有個問題就是由於一進來頁面是空的,所以loadmore函式會被觸發,在loadmore中加了一層判斷,判斷當前列表資料的長度是否為空,為空則停掉這個函式。避免其請求,菊花一直轉啊轉。然後優先呼叫initData(1),初始化資料,拿到了第一次資料。這時候如果你頁面向上拉,才會觸發loadmore函式請求第二頁資料,第二頁資料採用的是push方法,迴圈加進第一次請求的陣列中。

【3】判斷結束,根據介面返回來的total值,進行比較。當count值=total值,表明當前已經請求完資料可以進行收尾工作

【下拉重新整理的使用】

判:在頁面中<ion-content>裡是使用以下程式碼

<ion-refresher  pulling-text="釋放重新整理" refreshing-text="載入中" on-refresh="doRefresh()" ng-if="refresh" pulling-icon='ion-arrow-down-c' class="refresh"></ion-refresher>

判:on-refresh裡面是重新整理的方法,簡單來說參考上面上拉載入中的方法,可以看到就是再次呼叫initData(1),就是初次進入頁面時載入的方法,注意引數的重置為初始狀態,這裡需要修改下上拉載入的方法,就是在請求資料中新增重新整理停止的語句。這樣可以保證在下拉重新整理的時候,確保請求完資料時候再關閉重新整理圖示。這樣使用者體驗上比較好。,不多說貼上程式碼【程式碼是在上面介紹的上拉載入基礎上做的修改,主要是添加了一句紅色部分的程式碼】

$scope.getGoodsList = function(state) {
	try{
		pageno++;
		SearchService.getSearch(pageCount,pageno,k,t,token,function(isSuccess, response) {
			if(isSuccess) {	
			  try{
				console.log("呼叫函式時候的pageno:"+pageno);
				if(state == 1) {
					console.log("請求拿到了第一次資料");
					$scope.pSearch = response.data.rows;
					console.log(JSON.stringify($scope.pSearch));
		  			total = response.data.total;
                                        $scope.hasmore =$scope.hasMoreData();
                                        $scope.$broadcast('scroll.refreshComplete');
					if(response.data.total == 0) {
						$scope.tipRun = true;
					}
					 try{
					  if($scope.pSearch.length == 0) {
						 console.log('第一次請求沒有資料');
					   }
					}catch(err){
						
					}
				} else {
					if(state == 3 && $scope.pSearch.length == 0) {
						$scope.hasmore = false;
						$scope.$broadcast('scroll.infiniteScrollComplete');
					} else {
						for(var i = 0; i < response.data.rows.length; i++) {
							$scope.pSearch.push(response.data.rows[i]);
							++count;
							console.log(count + pageCount);
							if(count +pageCount >= total) {
								$scope.hasmore = false;
								break;
							}
						}
					}
				}
			   }catch(err){
                   console.log("請求不成功:原因可能token失效/網路狀態不佳")
			    }
			} else {
				
			}
			if(isLoadMore) {
				$scope.$broadcast('scroll.infiniteScrollComplete'); //廣播事件結束
					isLoadMore = false;
				}
			run = false;
			}
);
	}catch(error){
	alert("controller中商品搜尋呼叫函式失敗:"+error);
}
		};
	
      $scope.initData(1);//進入頁面直接載入初始資料


使用的重新整理函式的程式碼是
$scope.doRefresh=function(){
		$scope.noDataTip=false;//沒有更多資料的顯示
		count = 0;
	        total=0;
	        pageno =0;
	        pageCount = 10;
		$scope.initData(1);
	}

【6】清除介面資料中的空格

  中:trim()

for(var i=0;i<$scope.person.length;i++){
	$scope.person[i].peopleName=$scope.person[i].peopleName.trim();
}


【7】點擊出現彈框以及黑色遮罩層【其他方法制作】

  中:ionic自己有這個彈窗加上遮罩效果,但許多場景不好使用,黑色遮罩層可以考慮以下方法:

<ion-content>
 <div class="subject_black" ng-hide="subject_black" ng-click="hide()"></div>
.subject_black{
	width:100%;
	height:100%;
	background:black;
	opacity:0.4;
	position:absolute;
	top:0px;
	left:0px;
}
注意div放置在ion-content下一級首個子元素,利用content的寬度撐起黑色div實現全覆蓋,點選黑色div消失則直接在div上繫結ng-click即可

【優化】:在不需要計算高度的地方,可以直接使用ng-if來設定遮罩以及彈框.如果隨著頁面滾動,彈窗和遮罩需要同步移動當前位置,就需要使用ng-hide/ng-show,使用這兩個的缺陷是在ios上都會先閃一下再消失,在ipad上這種效果更加明顯,使用者體驗不是很好。對應的修改是:把彈框部分的屬性初始設定為position:relative,彈出顯示的時候修改為position:absolute;把遮罩層的高度初始化設定為0%,當彈出時修改為100%。彈出框為relative的時候會消失,0%時候遮罩層會消失。這樣保證了 頁面在在進來初始狀態就不會顯示那兩個,避免頁面閃動。出現的時候需要controllers中事件獲取對應div的id,然後使用css()方法修改屬性。

【8】獲取滑鼠點選物件的資料

$scope.brandFnc = function($element) {
$scope.text = $element.target.innerText;
console.log("點選資料為:" + $scope.text);
     };
頁面上對應使用:
<li ng-click="brandFnc($event)">
注意:括號引數不同

【9】頁面上渲染 頭/臉(A/B)此型別資料

  中:介面有可能傳回資料只有A,單個的時候不好處理/符號

<span>{{x.firstname}}</span>
{{x.firstname&&x.secondname?"/":""}}
<span>{{x.secondname}}</span>
上下各控制A和B的顯示,中間控制/的顯示

【10】介面資料拼接url,介面傳回資料html片段渲染頁面

  中:response.url是介面中傳來的資料,形式如:source/example/1/1.html, Locals.get('URL')是本地中的url頭:形如:http://172.168.12.22/拼接地址:

$scope.trustSrc = function(src) {
	return $sce.trustAsResourceUrl(src);
}
$scope.url = Locals.get('URL') + response.url;//簡單拼接
$scope.pointURL = $scope.trustSrc($scope.url); //解決報錯問題,將地址合法化
頁面上使用 ng-include 將html渲染頁面
<ion-content > 
    <div ng-include="pointURL"></div>
</ion-content>



【11】介面資料傳回中含有富文字的處理

  中

.filter('trustHtml', function ($sce) {
        return function (input) {
            return $sce.trustAsHtml(input);
        }
})

<p class="content" ng-bind-html="newsDetail.content | trustHtml"></p>
注意:這裡是ng-bind-html


【12】目錄中含有數字時,在ios上會被識別為電話號碼類的,會出現藍色下劃線,且其繫結新增的動態樣式不生效

中:在index.html中頭部新增

<meta name="format-detection" content="telephone=no"/>

【13】ionic與原生結合專案:頁面跳轉判斷

 中:原生A頁面直接跳到ionic的B頁面,ionic專案中,C頁面可以跳轉到B頁面,B頁面返回的時候需要做判斷,返回ionic專案頁面還是原生頁面。在頁面中重新寫按鈕返回事件,事件詳情如下;【注意引入相關服務】先判斷返回歷史有無,有就直接ionic專案中返回(h5),沒有就說明當前是原生跳過來的,那就呼叫cordova方法(具體的方法名由原生那邊提供)

Cordova.exec(function(result) {
			alert(result)
		   }, null, XXX, xxx, []);
這個程式碼就是原生已經寫好的,到時controllers中直接使用就能起到返回的效果【主要看原生提供】
$scope.back= function() {
		if($ionicHistory.backView()){
			$scope.$ionicGoBack();
		}
		else{
			Cordova.exec(function(result) {
			alert(result)
		   }, null, XXX, xxx, []);


		}
	};


【14】ionic專案在ios中出現頁面無法向上滑動的情況

 中:可以試試在頁面ion-content標籤中新增屬性【至今解決過兩個無法向上滑動問題】

<ion-content  overflow-scroll="true">


【15】點選事件觸發了兩次【冒泡事件】

 中:點選div時會觸發兩次函式,點選div實際也會點選ion-scroll,事件會向父元素傳遞,這裡需要阻止冒泡,使用$event.stopPropagation()

 <ion-scroll  direction="xy" style="width:100%; height:100%">
        <div style="width: 1000px; height: 1000px;" ng-click="show()" ></div>
  </ion-scroll>

修改後的程式碼如下:

 <ion-scroll  direction="xy" style="width:100%; height:100%">
        <div style="width: 1000px; height: 1000px;" ng-click="show();$event.stopPropagation()" ></div>
  </ion-scroll>

這樣點選就只會觸發一次

【16】ionic結合原生的專案在ios上卡死

 中:ionic專案在安卓上可以流暢執行,但是在ios上會經常出現卡死的情況,尤其是在原生與h5頁面互動請求資料的時候,目前是在頁面controllers中設定的時間函式,每次函式請求的時候都設定延遲300ms,猜想的由於angular.js的頁面資料過快繫結造成的,由於其工作狀態是時間監聽,一直佔著資源。有其他想法或者考慮的麻煩一同探討,畢竟這東西是曾經的夜夜難寐