zoukankan      html  css  js  c++  java
  • Angularjs 实现移动端在线测评效果

    注:此文所用的angular版本为 1.6


    一、运行效果图

    二、需求

    1. 点击选项时,背景变为黄色(即选中状态),并且自动切换到下一题

    2. 切换到下一题时,顶部进度随之改变

    3. 选中时要把对应的分值记录下来(因为要根据分值算出最后的测评结果)

    4. 通过向右滑动可以查看前面做过的题目

    5. 当前题目没选,无法切换到下一题

    6. 当选中最后一道题目时,切换到测评结果页

    三、具体实现

     题目json数据,总共10道题,这里为了节省篇幅,就只贴出3道了。 (Score是分数, OrderNo是答案序号)

    { "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":"您的收入需要用来供养其他人(如父母或子女)吗?", "AnswerList":[ {"Text":"不需供养其他人","Score":5,"OrderNo":1}, {"Text":"供养1人","Score":4,"OrderNo":2}, {"Text":"供养2人","Score":3,"OrderNo":3}, {"Text":"供养3人","Score":2,"OrderNo":4}, {"Text":"供养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', []);
    
        //控制器 - 风险测评
        app.controller('RiskTestController', ['$scope', '$http', RiskTestController]);
    
        function RiskTestController($scope, $http) {
            var vm = this;
    
            vm.letter = ['A', 'B', 'C', 'D', 'E'];  //答案编号
            vm.questionList = [];       //题目
            vm.point = 0;               //得分
            vm.showResult = false;      //是否显示结果页
    
            //加载数据       
            $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,  //当前第几题
                BIG = 9;    //最大索引值,因为总共10道题,所以是9(常量)
    
            //选择答案
            vm.OnClickAnswer = function (answer, $parentIndex) {
    
                var icons = document.querySelectorAll(".icon"),
                    curr = $parentIndex;        //当前题目索引
                    next = $parentIndex + 1;    //下一题索引
                    nextQuestion = vm.questionList[next];   //下一道题
    
                //当前问题的答案列表
                var answerList = vm.questionList[$parentIndex].AnswerList;
    
                //为每个答案对象添加属性 Selected, 默认值为false
                for (var i = 0, len = answerList.length; i < len; i++) {
                    answerList[i].Selected = false;
                }
    
                //将选中的答案设置为true (从而应用样式.selected 将背景色设置为黄色)
                answer.Selected = true;
    
                //判断是否为最后一道题
                if ($parentIndex < BIG) {   //不是最后一题
    
                    //改变顶部进度样式
                    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 {    //是最后一题
    
                    //改变顶部进度样式
                    icons[curr].classList.remove("icon-txt");
                    icons[curr].classList.add("icon-txt-active");
    
                    //计算分数
                    vm.point = CalcPoint();
    
                    //显示测评结果
                    vm.showResult = true;
                }
    
                //做了多少题
                count = CalcCount();
    
                //因为选中答案会自动切换到下一题,所以索引更新为next
                index = next;         
            }
    
            //计算分数
            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;
            }
    
            //计算当前做了多少道题
            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;
            }
    
            /** 触屏滑动效果处理 == 开始 == **/
    
            var offsetX = 0,    //手指滑动偏移量
                startX,         //滑动开始时的X轴坐标点
                startTime;      //手指滑动开始时间
    
            //触屏开始
            var startHandler = function (evt) {
    
                //每次触屏时将偏移量重置为0
                offsetX = 0;
    
                //记录X坐标
                startX = evt.touches[0].pageX;
    
                //取得时间戳
                startTime = new Date() * 1;
            };
    
            //触屏滑动
            var moveHandler = function (evt) {
                //阻止默认事件
                evt.preventDefault();
    
                //记录手指滑动的偏移量
                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;         
    
                //手指滑动时题卡跟着手指滑动(向右滑:[偏移量大于0,即正数,并且不是第一道题])
                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)');
                }
    
                //手指滑动时题卡跟着手指滑动(向左滑:[偏移量小于0,即负数,并且不是最后一题])
                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)');
                }
    
            };
    
            //触屏结束
            var endHandler = function (evt) {
                var boundary = window.innerWidth / 5,        //当手指滑动的偏移量为屏幕的5分之一时才进行切换
                    quickBoundary = 60,                        //当手指快速滑动时,偏移量为60即可 
                    endTime = new Date() * 1;                 //获取结束时间戳
    
                //判断是否为快速滑动
                if (endTime - startTime > 1000) {
    
                    //判断是向左滑还是向右滑
                    if (offsetX > 0) {
    
                        //判断是否达到切换偏移量
                        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();
                        }
                    }
                }
            };
    
            //向右滑动事件
            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--;
                }          
            }
    
            //右滑重置(当滑动距离没达到切换偏移量时,题卡回到原点)
            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)');
            }
    
            //向左滑动事件
            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++;
                }   
            }
    
            //左滑重置(当滑动距离没达到切换偏移量时,题卡回到原点)
            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)');
            }
    
            //监听滑动事件     
            var outer = document.getElementById("listBox");
            outer.addEventListener('touchstart', startHandler);
            outer.addEventListener('touchmove', moveHandler);
            outer.addEventListener('touchend', endHandler);
            
    
            /** 触屏滑动效果处理 == 结束 == **/
        }
    })(angular);

    大概就是这个样子了,代码都写了注释。大家有什么建议或发现什么问题请留言,帮忙优化优化,谢谢~

  • 相关阅读:
    poj 3264 Balanced Lineup
    poj 2762 Going from u to v or from v to u?
    hdu 3671 Boonie and Clyde
    zoj 3195 Design the city
    poj 1523 SPF
    Codeforces Polo the Penguin and Matrix
    MVC原理的简述(转)
    C#访问权限修饰符
    XML Schema介绍
    Sql批量删除/插入
  • 原文地址:https://www.cnblogs.com/similar/p/6371391.html
Copyright © 2011-2022 走看看