ionic项目实战-小白踩坑走起

来源:互联网 发布:windows无法检索有关 编辑:程序博客网 时间:2024/05/18 03:32

几个月的项目实战,走在适配安卓与ios的路上浪,总结经验,相互交流【2017/3/7起·持续更新】


【1】固定
 副标题固定可使用         

[html] view plain copy
  1. <span style="font-family:SimHei;font-size:14px;"><ion-header-bar class="bar bar-subheader"></ion-header-bar> </span>  
同理底部固定使用  ion-footer-bar

组件的页面固定,不随页面滚动:在ion-content之前使用ion-nav-buttons,在标签里面就是你需要固定的组件,div或其他,需要使用relative进行定位使用top调节位置。页面滚动的时候标题栏是不会动的,所以这里其实就是相对标题栏定位,实现固定

【注意:】这里需要用ion-nav-bar标签把它包起来,否则页面切换的时候上一页面的组件可能会存在下一页面中。包起来才能在页面切换中销毁掉

[html] view plain copy
  1.   
[html] view plain copy
  1. <ion-view>  
  2.     <ion-nav-bar>  
  3.         <ion-nav-buttons>  主要代码</ion-nav-buttons>      
  4.     </ion-nav-bar>  
  5.    <ion-content>       
  6.    </ion-content>  
  7. </ion-view>  

[html] view plain copy
  1.   

[html] view plain copy
  1.   

【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所占具体像素

主要触发函数:

[html] view plain copy
  1. $scope.tabSlide=function(num){  //num是当前点击对象的序号  
  2.         console.log(num);  
  3.         var other=typeNum%4;//tab 4分展示多余数的数量,<span style="font-family:SimHei;">typeNum是tab的总数</span>  
  4.         var session=typeNum/4//tab模块数量,4个为一模块  
  5.         var numLine=typeNum-other+1; //tab的邻界数,大于等于该数时为多余数序号  
  6.         var endLine=typeNum-4;  
  7.         if(num<4){  
  8.             $ionicScrollDelegate.$getByHandle('small').scrollTo(0);  
  9.         }  
  10.         else{  
  11.             $ionicScrollDelegate.$getByHandle('small').scrollTo(scrollWith*(num-3));  
  12.         }  
  13.           
  14.     }  
这里主要是我面板显示只会有4个,所以先考虑接口tab有多少个对应进行分组。scrollTo不是偏移量,是具体值。当点击小于4,则滚动条自然不用滚动,大于4则对应计算位置,触发滑动。代码不完整,更多是提供思路解决问题


【4】双向数据绑定设置为空
  初始化$scope.keyword={text:""};

 页面上使用keyword.text绑定ng-model

 设置为空使用命令$scope.keyword.text="";



【5】分页参数的使用(上拉加载)、下拉刷

  services.js中

[html] view plain copy
  1. .factory('SeaService', ['$http',  function($http) {  
  2.     var seaService = {};  
  3.     try  
  4.     {  
  5.     seaService.getSea = function(Count,no,Word, Type, Token,callback) {//这里参数对应看接口需要  
  6.         $http({  
  7.             method: 'POST',  
  8.             url: //请求数据地址,  
  9.             params: {       //k,t,pno等都是接口的参数名,对应看接口需要的名  
  10.                 k:Word,  
  11.                 t:Type,  
  12.                 pno:no,  
  13.                 psize:Count,  
  14.                 token:Token  
  15.             }  
  16.         }).success(function(response) {  
  17.             callback(true, response);  
  18.       
  19.         }).error(function() {  
  20.             callback(false, '');  
  21.         });  
  22.     }  
  23. }catch(error){  
  24. }  
  25.     return seaService;  
  26.   
  27. }])  


html中【数据渲染部分就不显示了】

[html] view plain copy
  1. <ion-infinite-scroll ng-if="hasmore" on-infinite="loadMore()" distance="1%"></ion-infinite-scroll>  



controllers.js中

[html] view plain copy
  1. .controller('SeaCtrl', ['$scope', 'SearchService', '$stateParams',  
  2. function($scope, SearchService, $stateParams,) {  
  3.       
  4.     $scope.pSearch = [];//定义空数组,用于存放所有列表数据渲染页面  
  5.     $scope.hasmore = true;  
  6.     var run = false;  
  7.     var count = 0;  
  8.     var total =0;  
  9.     var isLoadMore = false; //是否正在执行上拉  
  10.     var t = 1;  
  11.         var pageno=0 ;  
  12.     var pageCount=10;  
  13.   
  14.     /*判断是否加载完毕*/  
  15.     $scope.hasMoreData = function() {  
  16.         var hasMore = pageno * pageCount < total;  
  17.         console.log("pageno:" + pageno + "*" + "pageCount:" + pageCount + "----值" + total + " " + hasMore);  
  18.         return hasMore;  
  19.     };  
  20.    
  21.     $scope.loadMore = function() {  
  22.        if(total==$scope.pSearch.length){  
  23.             $scope.hasmore=false;  
  24.             console.log("total的值:"+total);  
  25.             $scope.$broadcast('scroll.infiniteScrollComplete');  
  26.         }  
  27.         isLoadMore = true;  
  28.         var old = $scope.pSearch;  
  29.         if(old.length != 0) {  
  30.             console.log("加载更多数据的入口");  
  31.             $scope.initData(3);  
  32.         }   
  33.     };  
  34.   
  35.     /* state:1初始化,3加载更多 */  
  36.     $scope.initData = function(state) {  
  37.         console.log(!run);  
  38.         if(!run) {  
  39.             run = true;  
  40.             if(state == 3) {  
  41.                 if(!$scope.hasmore) { // 加载完全  
  42.                     $scope.$broadcast('scroll.infiniteScrollComplete');  
  43.                     return;  
  44.                 }  
  45.             }  
  46.             $scope.getGoodsList(state);  
  47.   
  48.         } else {  
  49.             if(state == 3 || state == 1) {  
  50.                 $scope.$broadcast('scroll.infiniteScrollComplete'); //广播事件结束  
  51.                 isLoadMore = false;  
  52.             }  
  53.         }  
  54.     };  
  55.   
  56.   
  57.     $scope.getGoodsList = function(state) {  
  58.     try{  
  59.         pageno++;  
  60.         SearchService.getSearch(pageCount,pageno,k,t,token,function(isSuccess, response) {  
  61.             if(isSuccess) {   
  62.               try{  
  63.                 console.log("调用函数时候的pageno:"+pageno);  
  64.                 if(state == 1) {  
  65.                     console.log("请求拿到了第一次数据");  
  66.                     $scope.pSearch = response.data.rows;  
  67.                     console.log(JSON.stringify($scope.pSearch));  
  68.                     total = response.data.total;  
  69.                                         $scope.hasmore =$scope.hasMoreData();  
  70.   
  71.                     if(response.data.total == 0) {  
  72.                         $scope.tipRun = true;  
  73.                     }  
  74.                      try{  
  75.                       if($scope.pSearch.length == 0) {  
  76.                          console.log('第一次请求没有数据');  
  77.                        }  
  78.                     }catch(err){  
  79.                           
  80.                     }  
  81.                 } else {  
  82.                     if(state == 3 && $scope.pSearch.length == 0) {  
  83.                         $scope.hasmore = false;  
  84.                         $scope.$broadcast('scroll.infiniteScrollComplete');  
  85.                     } else {  
  86.                         for(var i = 0; i < response.data.rows.length; i++) {  
  87.                             $scope.pSearch.push(response.data.rows[i]);  
  88.                             ++count;  
  89.                             console.log(count + pageCount);  
  90.                             if(count +pageCount >= total) {  
  91.                                 $scope.hasmore = false;  
  92.                                 break;  
  93.                             }  
  94.                         }  
  95.                     }  
  96.                 }  
  97.                }catch(err){  
  98.                    console.log("请求不成功:原因可能token失效/网络状态不佳")  
  99.                 }  
  100.             } else {  
  101.                   
  102.             }  
  103.             if(isLoadMore) {  
  104.                 $scope.$broadcast('scroll.infiniteScrollComplete'); //广播事件结束  
  105.                     isLoadMore = false;  
  106.                 }  
  107.             run = false;  
  108.             }  
  109. );  
  110.     }catch(error){  
  111.     alert("controller中商品搜索调用函数失败:"+error);  
  112. }  
  113.         };  
  114.       
  115.       $scope.initData(1);//进入页面直接加载初始数据  
  116.   
  117.     }  
  118.   
  119. ])  
【1】下拉加载功能呢个标签的显示依赖ng-if=“hasmore”,hasmore为true的时候向上拉就会触发函数,为false时标签消失上拉加载功能自然消失。

【2】在controllers.js中最后一行可以看到调用initData(1)这个函数,一进入页面就会自然调用这个函数,,而且是优先,但是这里有个问题就是由于一进来页面是空的,所以loadmore函数会被触发,在loadmore中加了一层判断,判断当前列表数据的长度是否为空,为空则停掉这个函数。避免其请求,菊花一直转啊转。然后优先调用initData(1),初始化数据,拿到了第一次数据。这时候如果你页面向上拉,才会触发loadmore函数请求第二页数据,第二页数据采用的是push方法,循环加进第一次请求的数组中。

【3】判断结束,根据接口返回来的total值,进行比较。当count值=total值,表明当前已经请求完数据可以进行收尾工作



【下拉刷新的使用】

判:在页面中<ion-content>里是使用以下代码

[html] view plain copy
  1. <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),就是初次进入页面时加载的方法,注意参数的重置为初始状态,这里需要修改下上拉加载的方法,就是在请求数据中添加刷新停止的语句。这样可以保证在下拉刷新的时候,确保请求完数据时候再关闭刷新图标。这样用户体验上比较好。,不多说贴上代码【代码是在上面介绍的上拉加载基础上做的修改,主要是添加了一句红色部分的代码】

[plain] view plain copy
  1. $scope.getGoodsList = function(state) {  
  2.     try{  
  3.         pageno++;  
  4.         SearchService.getSearch(pageCount,pageno,k,t,token,function(isSuccess, response) {  
  5.             if(isSuccess) {   
  6.               try{  
  7.                 console.log("调用函数时候的pageno:"+pageno);  
  8.                 if(state == 1) {  
  9.                     console.log("请求拿到了第一次数据");  
  10.                     $scope.pSearch = response.data.rows;  
  11.                     console.log(JSON.stringify($scope.pSearch));  
  12.                     total = response.data.total;  
  13.                                         $scope.hasmore =$scope.hasMoreData();  
  14.                                         $scope.$broadcast('scroll.refreshComplete');  
  15.                     if(response.data.total == 0) {  
  16.                         $scope.tipRun = true;  
  17.                     }  
  18.                      try{  
  19.                       if($scope.pSearch.length == 0) {  
  20.                          console.log('第一次请求没有数据');  
  21.                        }  
  22.                     }catch(err){  
  23.                           
  24.                     }  
  25.                 } else {  
  26.                     if(state == 3 && $scope.pSearch.length == 0) {  
  27.                         $scope.hasmore = false;  
  28.                         $scope.$broadcast('scroll.infiniteScrollComplete');  
  29.                     } else {  
  30.                         for(var i = 0; i < response.data.rows.length; i++) {  
  31.                             $scope.pSearch.push(response.data.rows[i]);  
  32.                             ++count;  
  33.                             console.log(count + pageCount);  
  34.                             if(count +pageCount >= total) {  
  35.                                 $scope.hasmore = false;  
  36.                                 break;  
  37.                             }  
  38.                         }  
  39.                     }  
  40.                 }  
  41.                }catch(err){  
  42.                    console.log("请求不成功:原因可能token失效/网络状态不佳")  
  43.                 }  
  44.             } else {  
  45.                   
  46.             }  
  47.             if(isLoadMore) {  
  48.                 $scope.$broadcast('scroll.infiniteScrollComplete'); //广播事件结束  
  49.                     isLoadMore = false;  
  50.                 }  
  51.             run = false;  
  52.             }  
  53. );  
  54.     }catch(error){  
  55.     alert("controller中商品搜索调用函数失败:"+error);  
  56. }  
  57.         };  
  58.       
  59.       $scope.initData(1);//进入页面直接加载初始数据  



使用的刷新函数的代码是
[html] view plain copy
  1. $scope.doRefresh=function(){  
  2.         $scope.noDataTip=false;//没有更多数据的显示  
  3.         count = 0;  
  4.             total=0;  
  5.             pageno =0;  
  6.             pageCount = 10;  
  7.         $scope.initData(1);  
  8.     }  

【6】清除接口数据中的空格

  中:trim()

[html] view plain copy
  1. for(var i=0;i<$scope.person.length;i++){  
  2.     $scope.person[i].peopleName=$scope.person[i].peopleName.trim();  
  3. }  


【7】点击出现弹框以及黑色遮罩层【其他方法制作】

  中:ionic自己有这个弹窗加上遮罩效果,但许多场景不好使用,黑色遮罩层可以考虑以下方法:

[html] view plain copy
  1. <ion-content>  
  2.  <div class="subject_black" ng-hide="subject_black" ng-click="hide()"></div>  
  3. .subject_black{  
  4.     width:100%;  
  5.     height:100%;  
  6.     background:black;  
  7.     opacity:0.4;  
  8.     position:absolute;  
  9.     top:0px;  
  10.     left:0px;  
  11. }  
注意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】获取鼠标点击对象的数据

  

[html] view plain copy
  1. $scope.brandFnc = function($element) {  
  2. $scope.text = $element.target.innerText;  
  3. console.log("点击数据为:" + $scope.text);  
  4.      };  
页面上对应使用:
<li ng-click="brandFnc($event)">
注意:括号参数不同



【9】页面上渲染 头/脸(A/B)此类型数据

  中:接口有可能传回数据只有A,单个的时候不好处理/符号

[html] view plain copy
  1. <span>{{x.firstname}}</span>  
  2. {{x.firstname&&x.secondname?"/":""}}  
  3. <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/拼接地址:

[html] view plain copy
  1. $scope.trustSrc = function(src) {  
  2.     return $sce.trustAsResourceUrl(src);  
  3. }  
  4. $scope.url = Locals.get('URL') + response.url;//简单拼接  
  5. $scope.pointURL = $scope.trustSrc($scope.url); //解决报错问题,将地址合法化  


页面上使用 ng-include 将html渲染页面

[html] view plain copy
  1. <ion-content >   
  2.     <div ng-include="pointURL"></div>  
  3. </ion-content>  



【11】接口数据传回中含有富文本的处理

  中

[html] view plain copy
  1. .filter('trustHtml', function ($sce) {  
  2.         return function (input) {  
  3.             return $sce.trustAsHtml(input);  
  4.         }  
  5. })  

[html] view plain copy
  1. <p class="content" ng-bind-html="newsDetail.content | trustHtml"></p>  
注意:这里是ng-bind-html



【12】目录中含有数字时,在ios上会被识别为电话号码类的,会出现蓝色下划线,且其绑定添加的动态样式不生效

中:在index.html中头部添加

[html] view plain copy
  1. <meta name="format-detection" content="telephone=no"/>  




【13】ionic与原生结合项目:页面跳转判断

 中:原生A页面直接跳到ionic的B页面,ionic项目中,C页面可以跳转到B页面,B页面返回的时候需要做判断,返回ionic项目页面还是原生页面。在页面中重新写按钮返回事件,事件详情如下;【注意引入相关服务】先判断返回历史有无,有就直接ionic项目中返回(h5),没有就说明当前是原生跳过来的,那就调用cordova方法(具体的方法名由原生那边提供)

[html] view plain copy
  1. Cordova.exec(function(result) {  
  2.             alert(result)  
  3.            }, null, XXX, xxx, []);  
这个代码就是原生已经写好的,到时controllers中直接使用就能起到返回的效果【主要看原生提供】

[html] view plain copy
  1. $scope.backfunction() {  
  2.         if($ionicHistory.backView()){  
  3.             $scope.$ionicGoBack();  
  4.         }  
  5.         else{  
  6.             Cordova.exec(function(result) {  
  7.             alert(result)  
  8.            }, null, XXX, xxx, []);  
  9.   
  10.   
  11.         }  
  12.     };  


【14】ionic项目在ios中出现页面无法向上滑动的情况

 中:可以试试在页面ion-content标签中添加属性【至今解决过两个无法向上滑动问题】

[html] view plain copy
  1. <ion-content  overflow-scroll="true">  


【15】点击事件触发了两次【冒泡事件】

 中:点击div时会触发两次函数,点击div实际也会点击ion-scroll,事件会向父元素传递,这里需要阻止冒泡,使用$event.stopPropagation()

[plain] view plain copy
  1.   
[plain] view plain copy
  1. <ion-scroll  direction="xy" style="width:100%; height:100%">  
  2.        <div style="width: 1000px; height: 1000px;" ng-click="show()" ></div>  
  3.  </ion-scroll>  

修改后的代码如下:

[plain] view plain copy
  1. <ion-scroll  direction="xy" style="width:100%; height:100%">  
  2.        <div style="width: 1000px; height: 1000px;" ng-click="show();$event.stopPropagation()" ></div>  
  3.  </ion-scroll>  

这样点击就只会触发一次

【16】ionic结合原生的项目在ios上卡死

 中:ionic项目在安卓上可以流畅运行,但是在ios上会经常出现卡死的情况,尤其是在原生与h5页面交互请求数据的时候,目前是在页面controllers中设置的时间函数,每次函数请求的时候都设置延迟300ms,猜想的由于angular.js的页面数据过快绑定造成的,由于其工作状态是时间监听,一直占着资源。有其他想法或者考虑的麻烦一同探讨,毕竟这东西是曾经的夜夜难寐


原创粉丝点击