Angularjs 實(shí)現(xiàn)移動(dòng)端在線測(cè)評(píng)效果(推薦)
注:此文所用的angular版本為 1.6
一、運(yùn)行效果圖

二、需求
1. 點(diǎn)擊選項(xiàng)時(shí),背景(即選中狀態(tài)),并且自動(dòng)切換到下一題
2. 切換到下一題時(shí),頂部進(jìn)度隨之改變
3. 選中時(shí)要把對(duì)應(yīng)的分值記錄下來(因?yàn)橐鶕?jù)分值算出最后的測(cè)評(píng)結(jié)果)
4. 通過向右滑動(dòng)可以查看前面做過的題目
5. 當(dāng)前題目沒選,無法切換到下一題
6. 當(dāng)選中最后一道題目時(shí),切換到測(cè)評(píng)結(jié)果頁
三、具體實(shí)現(xiàn)
題目json數(shù)據(jù),總共10道題,這里為了節(jié)省篇幅,就只貼出3道了。 (Score是分?jǐn)?shù), OrderNo是答案序號(hào))
{ "Questions":
[
{
"Question":"您的年齡范圍:",
"AnswerList":[
{"Text":"30歲以下","Score":5,"OrderNo":0},
{"Text":"30-39歲","Score":4,"OrderNo":1},
{"Text":"40-49歲","Score":3,"OrderNo":2},
{"Text":"50-59歲","Score":2,"OrderNo":3},
{"Text":"60歲以上","Score":1,"OrderNo":4}]
},
{
"Question":"您的婚姻狀況為:",
"AnswerList":[
{"Text":"未婚","Score":5,"OrderNo":1},
{"Text":"已婚","Score":4,"OrderNo":2},
{"Text":"單身有婚史","Score":3,"OrderNo":3},
{"Text":"喪偶","Score":2,"OrderNo":4},
{"Text":"不詳","Score":1,"OrderNo":5}]
},
{
"Question":"您的收入需要用來供養(yǎng)其他人(如父母或子女)嗎?",
"AnswerList":[
{"Text":"不需供養(yǎng)其他人","Score":5,"OrderNo":1},
{"Text":"供養(yǎng)1人","Score":4,"OrderNo":2},
{"Text":"供養(yǎng)2人","Score":3,"OrderNo":3},
{"Text":"供養(yǎng)3人","Score":2,"OrderNo":4},
{"Text":"供養(yǎng)4人或以上","Score":1,"OrderNo":5}]
}
]
}Html代碼
<div class="wrapper" ng-controller="RiskTestController as vm">
<div class="process-box">
<ul>
<li class="page-icon"><span class="icon icon-txt">1</span></li>
<li class="page-icon"><span class="icon icon-txt">2</span></li>
<li class="page-icon"><span class="icon icon-txt">3</span></li>
<li class="page-icon"><span class="icon icon-txt">4</span></li>
<li class="page-icon"><span class="icon icon-txt">5</span></li>
<li class="page-icon"><span class="icon icon-txt">6</span></li>
<li class="page-icon"><span class="icon icon-txt">7</span></li>
<li class="page-icon"><span class="icon icon-txt">8</span></li>
<li class="page-icon"><span class="icon icon-txt">9</span></li>
<li class="page-icon"><span class="icon icon-txt">10</span></li>
</ul>
<div class="page-info">
已完成 {{vm.count}}/10
</div>
</div>
<ul class="list-box" id="listBox">
<li class="list-item" ng-repeat="question in vm.questionList track by $index" ng-class="{'first-li': $index == 0}">
<div class="question-box">
<div class="question">{{$index + 1}}. {{question.Question}}</div>
<ul class="answer">
<li class="answer-item"
ng-repeat="answer in question.AnswerList track by $index"
ng-click="vm.OnClickAnswer(answer, $parent.$index)"
ng-class="{'selected': answer.Selected}">
{{vm.letter[$index]}}. {{answer.Text}}
</li>
</ul>
</div>
</li>
</ul>
<div ng-show="vm.showResult">
<span>{{vm.point}}</span>
</div>
</div>核心CSS樣式代碼
.wrapper{
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.process-box{
width: 17.25rem;
height: 2.5rem;
line-height: 2.5rem;
background-color: #FFF;
margin: 1.5rem auto;
border-radius: 0.2rem;
}
.page-icon{
float: left;
font-size: 0.4rem;
color: #FFE7C9;
width: 1.32rem;
text-align: center;
}
.page-info{
font-size: 0.65rem;
color: #F3A84D;
}
.question-box{
width: 17.25rem;
background-color: #FFF;
margin-left: 0.75rem;
border-radius: 0.2rem;
}
.question{
font-size: 0.8rem;
color: #43689F;
padding: 1.1rem 0 0.8rem 0.75rem;
}
.answer-item{
font-size: 0.75rem;
color: #80A1D0;
border-top: 1px solid #EEE;
padding: 1.1rem 0 1.1rem 1.0rem;
}
.icon-txt{
background-color: orange;
border-radius: 0.5rem;
display: block;
width: 0.8rem;
height: 0.8rem;
line-height: 0.8rem;
margin: 0.95rem auto;
}
.icon-txt-active{
background-color: #FFE7C9;
border-radius: 0.3rem;
display: block;
width: 0.3rem;
height: 0.3rem;
line-height: 2.0rem;
color: #FFF;
margin: 1.25rem auto;
}
.list-item {
width: 100%;
position: absolute;
transform: translate3d(100%,0,0);
transition: transform 0.5s;
}
.first-li {
transform: translate3d(0,0,0);
}
.selected {
background-color: orange;
}控制器代碼(Controller)
(function (agr) {
//模塊 - app
var app = agr.module('app', []);
//控制器 - 風(fēng)險(xiǎn)測(cè)評(píng)
app.controller('RiskTestController', ['$scope', '$http', RiskTestController]);
function RiskTestController($scope, $http) {
var vm = this;
vm.letter = ['A', 'B', 'C', 'D', 'E']; //答案編號(hào)
vm.questionList = []; //題目
vm.point = 0; //得分
vm.showResult = false; //是否顯示結(jié)果頁
//加載數(shù)據(jù)
$http({
method: 'GET',
url: '/Service/RiskTest',
}).then(function (resp) {
vm.questionList = resp.data.Questions;
}, function (resp) {
console.log("ERROR", resp);
});
var lis = document.querySelectorAll(".list-item"), //題目列表
count = 0, //做了多少道題
index = 0, //當(dāng)前第幾題
BIG = 9; //最大索引值,因?yàn)榭偣?0道題,所以是9(常量)
//選擇答案
vm.OnClickAnswer = function (answer, $parentIndex) {
var icons = document.querySelectorAll(".icon"),
curr = $parentIndex; //當(dāng)前題目索引
next = $parentIndex + 1; //下一題索引
nextQuestion = vm.questionList[next]; //下一道題
//當(dāng)前問題的答案列表
var answerList = vm.questionList[$parentIndex].AnswerList;
//為每個(gè)答案對(duì)象添加屬性 Selected, 默認(rèn)值為false
for (var i = 0, len = answerList.length; i < len; i++) {
answerList[i].Selected = false;
}
//將選中的答案設(shè)置為true (從而應(yīng)用樣式.selected 將背景色設(shè)置)
answer.Selected = true;
//判斷是否為最后一道題
if ($parentIndex < BIG) { //不是最后一題
//改變頂部進(jìn)度樣式
icons[curr].classList.remove("icon-txt");
icons[curr].classList.add("icon-txt-active");
//切換到下一題
lis[curr].style.webkitTransform = 'Translate3d(-100%,0,0)';
nextQuestion && (lis[next].style.webkitTransform = 'Translate3d(0,0,0)');
} else { //是最后一題
//改變頂部進(jìn)度樣式
icons[curr].classList.remove("icon-txt");
icons[curr].classList.add("icon-txt-active");
//計(jì)算分?jǐn)?shù)
vm.point = CalcPoint();
//顯示測(cè)評(píng)結(jié)果
vm.showResult = true;
}
//做了多少題
count = CalcCount();
//因?yàn)檫x中答案會(huì)自動(dòng)切換到下一題,所以索引更新為next
index = next;
}
//計(jì)算分?jǐn)?shù)
var CalcPoint = function () {
var point = 0;
for (var i = 0, lenq = vm.questionList.length; i < lenq; i++) {
for (var k = 0, lena = vm.questionList[i].AnswerList.length; k < lena; k++) {
if (vm.questionList[i].AnswerList[k].Selected) {
point += vm.questionList[i].AnswerList[k].Score;
}
}
}
return point;
}
//計(jì)算當(dāng)前做了多少道題
var CalcCount = function(){
var count = 0;
for (var i = 0, lenq = vm.questionList.length; i < lenq; i++) {
for (var k = 0, lena = vm.questionList[i].AnswerList.length; k < lena; k++) {
if (vm.questionList[i].AnswerList[k].Selected) {
count++;
}
}
}
return count;
}
/** 觸屏滑動(dòng)效果處理 == 開始 == **/
var offsetX = 0, //手指滑動(dòng)偏移量
startX, //滑動(dòng)開始時(shí)的X軸坐標(biāo)點(diǎn)
startTime; //手指滑動(dòng)開始時(shí)間
//觸屏開始
var startHandler = function (evt) {
//每次觸屏?xí)r將偏移量重置為0
offsetX = 0;
//記錄X坐標(biāo)
startX = evt.touches[0].pageX;
//取得時(shí)間戳
startTime = new Date() * 1;
};
//觸屏滑動(dòng)
var moveHandler = function (evt) {
//阻止默認(rèn)事件
evt.preventDefault();
//記錄手指滑動(dòng)的偏移量
offsetX = evt.touches[0].pageX - startX;
var curr = index,
prev = index - 1,
next = index + 1,
prevQuestion = vm.questionList[prev],
nextQuestion = vm.questionList[next],
width = window.innerWidth;
//手指滑動(dòng)時(shí)題卡跟著手指滑動(dòng)(向右滑:[偏移量大于0,即正數(shù),并且不是第一道題])
if (offsetX > 0 && index > 0) {
lis[curr].style.webkitTransform = 'Translate3d(' + offsetX + 'px, 0, 0)';
prevQuestion && (lis[prev].style.webkitTransform = 'Translate3d(' + (offsetX - width) + 'px, 0, 0)');
}
//手指滑動(dòng)時(shí)題卡跟著手指滑動(dòng)(向左滑:[偏移量小于0,即負(fù)數(shù),并且不是最后一題])
if (offsetX < 0 && index < count) {
lis[curr].style.webkitTransform = 'Translate3d(' + offsetX + 'px, 0, 0)';
nextQuestion && (lis[next].style.webkitTransform = 'Translate3d(' + (offsetX + width) + 'px, 0, 0)');
}
};
//觸屏結(jié)束
var endHandler = function (evt) {
var boundary = window.innerWidth / 5, //當(dāng)手指滑動(dòng)的偏移量為屏幕的5分之一時(shí)才進(jìn)行切換
quickBoundary = 60, //當(dāng)手指快速滑動(dòng)時(shí),偏移量為60即可
endTime = new Date() * 1; //獲取結(jié)束時(shí)間戳
//判斷是否為快速滑動(dòng)
if (endTime - startTime > 1000) {
//判斷是向左滑還是向右滑
if (offsetX > 0) {
//判斷是否達(dá)到切換偏移量
if (offsetX >= boundary) {
MoveToRight();
} else {
ResetMoveRight();
}
} else{
if (offsetX < -boundary) {
MoveToLeft();
} else {
ResetMoveLeft();
}
}
} else {
if (offsetX > 0) {
if (offsetX >= quickBoundary) {
MoveToRight();
} else {
ResetMoveRight();
}
} else {
if (offsetX < -quickBoundary) {
MoveToLeft();
} else {
ResetMoveLeft();
}
}
}
};
//向右滑動(dòng)事件
var MoveToRight = function () {
var curr = index,
prev = index -1,
prevQuestion = vm.questionList[prev];
if (curr > 0) {
lis[curr].style.webkitTransform = 'Translate3d(100%, 0, 0)';
prevQuestion && (lis[prev].style.webkitTransform = 'Translate3d(0, 0, 0)');
index--;
}
}
//右滑重置(當(dāng)滑動(dòng)距離沒達(dá)到切換偏移量時(shí),題卡回到原點(diǎn))
var ResetMoveRight = function () {
var curr = index,
prev = index -1,
prevQuestion = vm.questionList[prev];
lis[curr].style.webkitTransform = 'Translate3d(0, 0, 0)';
prevQuestion && (lis[prev].style.webkitTransform = 'Translate3d(-100%, 0, 0)');
}
//向左滑動(dòng)事件
var MoveToLeft = function () {
var curr = index,
next = index + 1,
nextQuestion = vm.questionList[next];
if (curr < count) {
lis[curr].style.webkitTransform = 'Translate3d(-100%, 0, 0)';
nextQuestion && (lis[next].style.webkitTransform = 'Translate3d(0, 0, 0)');
index++;
}
}
//左滑重置(當(dāng)滑動(dòng)距離沒達(dá)到切換偏移量時(shí),題卡回到原點(diǎn))
var ResetMoveLeft = function () {
var curr = index,
next = index + 1,
nextQuestion = vm.questionList[next];
lis[curr].style.webkitTransform = 'Translate3d(0, 0, 0)';
nextQuestion && (lis[next].style.webkitTransform = 'Translate3d(100%, 0, 0)');
}
//滑動(dòng)事件
var outer = document.getElementById("listBox");
outer.addEventListener('touchstart', startHandler);
outer.addEventListener('touchmove', moveHandler);
outer.addEventListener('touchend', endHandler);
/** 觸屏滑動(dòng)效果處理 == 結(jié)束 == **/
}
})(angular);相關(guān)文章
Angular.js中用ng-repeat-start實(shí)現(xiàn)自定義顯示
大家都知道Angular.js可以用ng-repeat來顯示列表數(shù)據(jù),可是如果想要自定義顯示數(shù)據(jù)列表的話ng-repeat就實(shí)現(xiàn)不了了,這個(gè)時(shí)候可以利用ng-repeat-start 和 ng-repeat-end來實(shí)現(xiàn),下面通過本文來詳細(xì)看看實(shí)現(xiàn)的方法吧。2016-10-10
詳解Angular-ui-BootStrap組件的解釋以及使用
這篇文章主要介紹了詳解Angular-ui-BootStrap組件的解釋以及使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
AngularJS入門教程之 XMLHttpRequest實(shí)例講解
本文主要講解 AngularJS XMLHttpRequest,這里給大家整理相關(guān)資料并提供實(shí)例代碼,有需要的小伙伴參考下2016-07-07
Angular實(shí)現(xiàn)svg和png圖片下載實(shí)現(xiàn)
這篇文章主要介紹了Angular實(shí)現(xiàn)svg和png圖片下載實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
angularjs創(chuàng)建彈出框?qū)崿F(xiàn)拖動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了angularjs創(chuàng)建彈出框?qū)崿F(xiàn)拖動(dòng)效果的相關(guān)資料,angularjs modal模態(tài)框創(chuàng)建可拖動(dòng)的指令,感興趣的小伙伴們可以參考一下2016-01-01

