ionic + cordova+angularJs 搭建的H5 App完整版总结
为期半个月的项目实践开发,已完整告一段落,团队小组获得第一名,辛苦总算没有白费,想起有一天晚上,整个小组的人,联调到12点才从公司回去,真是心酸。这里总结一下,项目过程中遇到的问题
和感悟。哈哈,放张集体照。嘿嘿,项目所有的不同的team的小伙伴,一群优秀的小伙伴(大多都来自高校211,985)么么哒.下面介绍下我们组的产品和问题。
项目已放在github上:https://github.com/foreverjiangting/myApp/tree/master/myApp/myApp
一:项目效果展示
先展示一下我们做的产品,主要是做一个投票的APP,包括用户登录,注册,答卷,查看答卷详情,排行榜等功能。后台可创建问卷,分发问卷,增加单选题和多选题,创建问卷题目,我这边前端的app将其显
示出来。基本上可以满足需求,但还有很多不完善的地方。
二:制作功能问题总结
先看下核心功能,用户进行单选,多选后,将保存用户的答案,传递后后端,然后在展示详情里面将用户的答案进行展示出来。这里先贴下代码。
<ion-slide-box show-pager="false" on-slide-changed="onSlideChanged(index)" active-slide="currentIndex"> <ion-slide class="set-container" ng-repeat="value in objData" repeat-done="repeatDone()" > <div class="swiper-slide swiper-slide-duplicate swiper-slide-active" style="width: 349px; margin-right: 30px;"> <div class="scores" > <h3>{{data.title}}</h3> <div class="f"><span id="span-text">{{$index+1}}</span>{{value.title}}</div> <div class="choose"> <div class="input" ng-repeat="(key,value2) in value.items"> <label for="26"> <input type="radio" name="radio{{$parent.$index}}" class="radio" value="{{key}}" ng-model= "selectedValue.radioData[$parent.$index]"> <span >{{value2}}</span> </label> </div> </div> </div> </div> </ion-slide>
这里有几个问题,由于是公用同一个模板,每一个ion-slide就是一页,且一页下面有多个选项。问题如下:
1.如何区分不同个ion-slide下的radio ?贴下代码,只要给name添加就可以。$parent.$index即可
<input type="radio" name="radio{{$parent.$index}}" class="radio"
2.如何获取用户选择的当前页的答案?使用ng-model即可,将用户选择的答案分别存在一个数组里面。
ng-model= "selectedValue.radioData[$parent.$index]">
基本上也没啥难点,就是方法要知道。用户填写答案完成后,进行保存,我们需要获取用户提交的所有答案。看下代码。
$scope.submitData = {}; //用户提交完毕,当前的问卷被提交,修改其状态为已完成。可在已完成的栏目进行查看 $scope.submitSuccess = function(){ var radioJsonData = $scope.selectedValue.radioData; var radioObject = []; for(var k in radioJsonData){ radioObject.push(radioJsonData[k]); } console.log('3333') console.log(radioObject); console.log(radioJsonData) //获取radioData的长度,判断用户选择的数据是否完整 var radioLength = 0; var getRadioLength = function(radioJsonData){ for(var item in radioJsonData){ radioLength++; } return radioLength; } if(getRadioLength(radioJsonData) == $scope.serveLength-1){ var submitData = window._single = { "single":radioObject }; var submitId = window._id = { "id" : $stateParams.timuId } console.log(JSON.stringify(submitData)); var alertPopup = $ionicPopup.alert({ title: '保存成功', template: '您的单选题已完成,请继续答题!' }); alertPopup.then(function(res) { history.go(-1); }); } else{ var alertPopup = $ionicPopup.alert({ title: '提交失败', template: '您的问卷未完成,请返回查看详情!' }); alertPopup.then(function(res) { console.log('提交失败'); }); } };
3.再来看下多选题,跟单选题有点区别。
<ion-slide-box show-pager="false" on-slide-changed="onSlideChanged(index)" active-slide="currentIndex"> <ion-slide class="set-container" ng-repeat="value in objData" repeat-done="repeatDone()" > <div class="swiper-slide swiper-slide-duplicate swiper-slide-active" style="width: 349px; margin-right: 30px;"> <div class="scores"> <h3>{{data.title}}</h3> <div class="f"><span id="span-text">{{$index+1}}</span>{{value.title}}</div> <div class="choose" > <div class="input" ng-repeat="(key,value2) in value.items"> <label for="26"> <input type="checkbox" name="radio{{$parent.$index}}" class="radio" ng-model = "selected[$parent.$index][$index]" > <span style="margin-left: 30px;">{{value2}}</span> </label> </div> </div> </div> </div> </ion-slide>
问题如下:
1.如何在多选里面选中多个答案呢?
ng-model = "selected[$parent.$index][$index]"
这种方法是最简单的,虽然不是我们要的,但之后再做一下解析即可。数组里面的数据是这样子的。因为我们只需要保存用户选择的答案的当前题目的index,保存以1,2,3,4的形式保存即可。
看下解析的代码如下:
$scope.nextSlide = function(){ var slideIndex = $ionicSlideBoxDelegate.currentIndex(); $scope.connectedData = $scope.selected.map(function(item){ var connectSelected = []; for(var i in item){ if(item[i]){ connectSelected.push(parseInt(i)+1); } } return connectSelected.join('/'); //进行解析,以/进行分割 }) if( $scope.connectedData == null){ var alertPopup = $ionicPopup.alert({ template: '您还没有选择,请选择答案!' }); }else if( $scope.connectedData[slideIndex] == null && slideIndex != $scope.serveLength-1 ){ var alertPopup = $ionicPopup.alert({ template: '您还没有选择,请选择答案!' }); return true; }else { $ionicSlideBoxDelegate.next(); } return ; console.log('test:'+JSON.stringify( $scope.connectedData)); //$ionicSlideBoxDelegate.next(); };
3.既然单选题和多选题都有答案了,现在就是提交用户答案了。解决不同controller之间的数据通信,本来之前用的$rootscope,不知道为什么不行,后来学霸告诉我直接
存在window下面。于是简单粗暴的解决了问题。
先看下代码吧,我们前端需要提交给后端数据包括问卷的ID,单选题答案,多选题答案。下面是提交的代码。
.controller('chooseCtrl',['$scope','$ionicPopup', '$timeout', '$stateParams','$http','$ionicScrollDelegate','$location' ,function($scope,$ionicPopup, $timeout, $stateParams,$http,$ionicScrollDelegate,$location){ $scope.jump = function(url){ window.location = url; } $scope.chooseId = $stateParams.timuId; //获取问卷的Id console.log( $scope.chooseId); var submitData = { "id" : $scope.chooseId } var objData = []; //刚开始渲染数据,获取整个问卷的data,单选存在一个数组,多选存在一个数组 $http({ // url : "../data/api.json", url : "http://10.32.33.4:8080/ivotel-management/questionnaire/selectQuestionnaireDetail", method : "get", params: submitData, headers: { 'Content-Type': 'application/json;charset=UTF-8' } }).success(function(data) { var arr =data.questionnaireQuestionList; //进行解析 var singleData = [] ; var mutilData = []; for(var i=0;i<arr.length;i++){ objData[i] = arr[i].responseQuestion; } // console.log(JSON.stringify(objData)); //获取所有的题目对象 for(var i in objData){ if(objData[i].questiontype == 1){ singleData.push(objData[i]); }else if(objData[i].questiontype == 2){ mutilData.push(objData[i]); } } window._singleData = singleData; window._singleData_length = singleData.length; window._mutilData = mutilData; window._mutilData_length = mutilData.length; window.totalQuestionData = data ; //console.log(JSON.stringify(singleData)); //console.log(JSON.stringify(mutilData)); $scope.data = data; $scope.serveData = data.questionnaireQuestionList[0].qqid; }).error(function(){ console.log('error'); }); //用户填写完成后,将用户答案保存,并一起传递给后端 $scope.submit = function(){ if(window._multi == null){ window._multi = []; } var submitTotalData = [ window._id , window._single , window._multi ] ; $http({ url : "http://10.32.33.4:8080/ivotel-examuser/questionnairePapers/Submit", method : "post", data : submitTotalData, headers: { 'Content-Type': 'application/json;charset=UTF-8' }, withCredentials :true }).success(function(data) { console.log('success'); }).error(function(){ console.log('error'); }); var alertPopup = $ionicPopup.alert({ title: '提交成功', template: '您的问卷已完成,请返回查看详情!' }); alertPopup.then(function(res) { history.go(-1); }); console.log('test: ' + JSON.stringify( submitTotalData)); } }])
输出时用户提交的所有答案格式如下:
将不同的controller里面的值,分别存在window下面的某一个属性下面,即可在全局中进行使用。
4.OK ,既然答案都已经保存好啦,现在,我们需要将答案展示出来。在详情页面列表中。
看下后端传给我们的数据格式如下:
{ "answer": { //单选 "1": "4", //第一题,用户选择第四个答案 "2": "1", //第二题,用户选择第一个答案 "3":"3" //第三题,用户选择第三个答案 }, "multi": { //多选 "4": "1/2/3", //第四题,用户选择1,2,3答案 "5": "1/3/4", //第五题,用户选择1,3,4答案 "6": "1/3/4" //第六题,用户选择1,3,4答案 } }
看下效果图,我们主要是做两件事,1.进行解析,将用户的答案,呈现出来。2.根据答案,选中用户当前的radio的状态。
这里直接贴下代码,解析的过程都在代码中。比较繁琐。
关于单选的话,根绝单选直接选中当前的radio,比较好说,直接使用下面的方法即可:
<ion-slide class="set-container" ng-repeat="value in singleData" repeat-done="repeatDone()" > <div class="swiper-slide swiper-slide-duplicate swiper-slide-active" style="width: 349px; margin-right: 30px;"> <div class="scores" > <h3>{{data.title}}</h3> <div class="f"><span id="span-text">{{$index+1}}</span>{{value.title}}</div> <div class="choose"> <div class="input" ng-repeat="(key,value2) in value.items"> <label for="26"> <input type="radio" name="radio{{$parent.$index}}" class="radio" value="{{value2}}" ng-checked="$index == selectedIndex-1"> <span >{{value2}}</span> </label> </div> </div> </div> </div> </ion-slide>
即直接使用下面的方法:ng-checked = "$index == selectedIndex -1"即可.
ng-checked="$index == selectedIndex-1">
这里解析的代码也贴一下:
.controller('listItemCtrl',['$scope','$ionicPopup', '$timeout', '$stateParams','$http','$ionicScrollDelegate','$location' ,'$ionicSlideBoxDelegate','$ionicHistory', function($scope,$ionicPopup, $timeout,$stateParams,$http,$ionicScrollDelegate,$location,$ionicSlideBoxDelegate,$ionicHistory){ // $ionicHistory.nextViewOptions({ // disableBack: true // }); $scope.repeatDone = function() { $ionicSlideBoxDelegate.update(); }; var objData = []; $scope.selectedValue = {}; $scope.radioData = []; $scope.wenjuanId = $stateParams.timuId; //获取问卷的Id console.log('问卷Id:' + $scope.wenjuanId); var submitData = { "id" : $scope.wenjuanId } $scope.serveData = 0; $scope.objData = null; $scope.jsonRadio = []; $scope.newJsonData = []; //根据对应的题目索引,得到正确的题目 $scope.newMulitJsonData = []; $scope.currentIndex = 0; $scope.answerData = null; //所有的单选题的答案 $scope.answerMutleData = null; $scope.jsonItemData = null; $scope.selectedIndex = 0; $scope.answerArray = []; $scope.singleData = []; //所有的单选题 $scope.multiData = []; $scope.serveLength = 0; $scope.selectedMulitIndex = 0; $scope.chooseMulitData = []; $scope.single_length = 0; $scope.muiteKey = 0; $scope.arrData = []; $http({ url : "../data/doing.json", //url : "http://10.32.33.4:8080/ivotel-examuser/questionnairePapers/PaperDetail", method : "get", params: submitData, headers: { 'Content-Type': 'application/json;charset=UTF-8' }, withCredentials :true }).success(function(data) { $scope.answerData = data.answer; console.log($scope.answerData); //得到用户选择的答案 {1: "1", 2: "2"} var arr = data.questionnaireTemp.questionnaireQuestionList; //进行解析 for(var i=0; i< arr.length;i++){ //获取所有的题目对象 objData[i] = arr[i].responseQuestion; } $scope.data = data; $scope.objData = objData; $scope.serveLength = objData.length; //console.log( $scope.serveLength) //console.log(JSON.stringify( $scope.objData)); for(var i in objData){ //将单选题 和 多选题分别存在不同的数组里面 if(objData[i].questiontype == 1){ $scope.singleData.push(objData[i]); $scope.single_length = $scope.singleData.length -1 ; }else if(objData[i].questiontype == 2){ $scope.multiData.push(objData[i]); } } //如果为单选的话,为 $scope.singleData for(var i in $scope.answerData){ //i为key值开始 if(i == ($ionicSlideBoxDelegate.currentIndex()+1)){ $scope.newJsonData.push($scope.singleData[i-1].items[($scope.answerData[i])]); } } $scope.selectedIndex = parseInt($scope.answerData[$ionicSlideBoxDelegate.currentIndex()+1]) ; console.log('selectedIndex : ' +$scope.selectedIndex) console.log('jsonNewData:' + JSON.stringify( $scope.newJsonData)); //如果为多选的话,为$scope.multiData $scope.answerMutleData = data.multi; console.log( JSON.stringify($scope.answerMutleData)); //对数组进行解析 var temp = 0; for(var i in $scope.answerMutleData){ //i为3 var arr = $scope.answerMutleData[i].split('/'); $scope.arrData = arr ; for (var i in arr){ // $scope.muiteKey = arr[i]; //获取key值,并赋值给全局变量 } // $scope.muiteKey = arr[$ionicSlideBoxDelegate.currentIndex()] console.log('arr : ' + JSON.stringify(arr)); //[1,2,3] console.log('key: ' + JSON.stringify($scope.arrData)); for(var j=0;j < arr.length; j++){ console.log('test: ' +temp ); if(i == ($ionicSlideBoxDelegate.currentIndex()+1)){ $scope.newMulitJsonData.push($scope.multiData[temp].items[(arr[j])]); } } temp++; console.log('arrDate:' + JSON.stringify($scope.arrData)); } console.log($scope.newMulitJsonData); //所有的单选全部展示完成后,开始展示所有的多选 $scope.selectedMulitIndex = parseInt($scope.answerMutleData[$ionicSlideBoxDelegate.currentIndex()+1]) ; $scope.muiteKey = parseInt($scope.answerMutleData[$ionicSlideBoxDelegate.currentIndex()+1]) ; console.log( $scope.selectedMulitIndex); }).error(function(){ console.log('error'); }); $scope.jsonItemData = []; var osingMes = document.getElementById('singleMessage'); var omulit = document.getElementById('muiltMessage'); $scope.onSlideChanged = function(index){ $scope.currentIndex = index; for(var i in $scope.answerData){ $scope.answerArray.push($scope.answerData[i]); } console.log('index22:' + index); $scope.selectedIndex = parseInt($scope.answerData[$ionicSlideBoxDelegate.currentIndex()+1])-1 ; console.log('selectedIndex : ' +$scope.selectedIndex) for(var i in $scope.answerData){ if(i == ($ionicSlideBoxDelegate.currentIndex()+1)){ $scope.newJsonData.push($scope.singleData[i-1].items[($scope.answerData[i])]); $scope.selectedIndex = $scope.answerData[i] - '0' ; } console.log('index:' + $scope.selectedIndex) } // if($ionicSlideBoxDelegate.currentIndex()+1 > $scope.serveLength){ // osingMes.style.display = 'none'; // omulit.style.display = 'block'; // } console.log('jsonNewData:' + JSON.stringify( $scope.newJsonData)); //如果为多选的话,为$scope.multiData // $scope.answerMutleData = data.multi; console.log( JSON.stringify($scope.answerMutleData)); //对数组进行解析 var temp = 0; for(var i in $scope.answerMutleData){ //i为3 // var b = $scope.newMulitJsonData; //将上一次的值赋给b console.log('length :' + $scope.newMulitJsonData.length); var arr = $scope.answerMutleData[i].split('/'); for(var j=0;j < arr.length; j++){ console.log('test: ' + temp ); if(i == ($ionicSlideBoxDelegate.currentIndex()+1)){ if($scope.newMulitJsonData[j] == null){ //判断之前的所有选项是否为空 $scope.newMulitJsonData.push($scope.multiData[temp].items[(arr[j])]); $scope.muiteKey = $scope.multiData[temp] - '0'; }else{ $scope.newMulitJsonData = []; $scope.newMulitJsonData.push($scope.multiData[temp].items[(arr[j])]); } } console.log('json: '+ JSON.stringify($scope.newMulitJsonData)); } temp++; //[1,2,3] } console.log(JSON.stringify($scope.newMulitJsonData)); for(var i in $scope.newMulitJsonData){ console.log('i:'+ i); } //console.log($scope.newMulitJsonData); //得到的正确答案没问题 //所有的单选全部展示完成后,开始展示所有的多选 $scope.selectedMulitIndex = parseInt($scope.answerMutleData[$ionicSlideBoxDelegate.currentIndex()+1]) ; console.log( $scope.selectedMulitIndex); }; $scope.nextSlide = function(){ if($ionicSlideBoxDelegate.currentIndex()+1 != $scope.serveLength) { $ionicSlideBoxDelegate.next(); }else { var alertPopup = $ionicPopup.alert({ template: '亲,已经最后一题,木有了哦!' }); alertPopup.then(function(res) { // window.location.reload(); // history.go(-1); }); } }; $scope.startSlide = function(){ $ionicSlideBoxDelegate.previous(); }; }])
5.前后端跨域的问题。
由于angularjs的$http请求与ajax还是有些区别的,总是会存在跨域的问题,如何解决呢?加个 withCredentials :true 即可。
$http({ url : "http://10.32.33.4:8080/ivotel-examuser/questionnairePapers/Submit", method : "post", data : submitTotalData, headers: { 'Content-Type': 'application/json;charset=UTF-8' }, withCredentials :true }).success(function(data) { console.log('success'); }).error(function(){ console.log('error'); });
})
OK,基本上整个核心的功能点都已经讲解清楚啦。问题还是遇到不少,感谢从不拒绝我问题的shu,给了我很大的帮助。嘿嘿,么么哒!
三:总结
经过这个月的项目实践,熟悉了不少ng的写法,虽然以前也接触过,但好像都不是很熟,而且一个完整的APP的搭建流程也熟悉很多。其次,想说到前后端合作的问题,定契约的问题,沟通问题
感觉一个项目下来,反正各种问题都碰到,大家一起吵啊,争啊,各有各的想法,拍桌子啊,前后端互相抱怨啊,虽然意见各有不同,哈哈哈,还是很高兴的!起码团队很有活力,很有想法,要都是
不吭声,那才恐怖,自己搞自己的,谁知道你什么想法。哈哈哈,喜欢我们的团队,一个个都棒棒的!另外呢,做项目的时候呢,要知道每个人都有自己的想法,所以,不要一昧的否认别人的想法,觉
得自己就是对的(傻逼), 学会倾听,很关键。团队获得了第一名,大家都很开心,当晚我们组大家一起去吃了海鲜自助。哈哈,放张照片!
还是喜欢和自己年龄相仿的人一起工作,做项目,开开玩笑,多开心。每天充满了激情和活力,沟通无代沟,都是90后,一群年轻人,多好!可是,事与愿违啊!接下来,还是得适应不同年龄段的人!
作者:婷风
出处:http://www.cnblogs.com/jtjds/p/6128539.html
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意
转载文章之后必须在 文章页面明显位置给出作者和原文连接否则保留追究法律责任的权利。