zoukankan      html  css  js  c++  java
  • 360前端星计划作业

    任务要求

    在移动设备上,“手势密码”是一个很常见的UI。实现一个移动网页,允许用户设置手势密码和验证手势密码。已设置的密码记录在本地 localStorage 中。
    原型界面如下:

    操作流程如下图所示:

    思路

    实现原理:利用HTML5的canvas,绘制未解锁的圆,并利用touch事件来绘制解锁的圆与路径。
    代码下载

    思考流程

    首先第一步,分析界面上的元素,主要有标题区域,解锁区域,信息提示区域,模式选择区域四个区域。因此,整体布局呈现由上至下排布的,但是需要注意在不同尺寸上设备的兼容性情况。因此考虑到利用js查询当前设备window的大小(即window.innerWidthwindow.innerHeight;)。从而根据相应大小动态计算参数进行布局。

    //DOM的初始化
    SignLock.prototype.initDOM = function(){};
    

    然后第二步,分析整个解锁过程中,需要处理的动画情况。

    • 初始状态下,需要绘制所有的初始圆
    • 解锁或者设置密码状态下,需要实时更新绘制选中的圆
    • 解锁或者设置密码过程中,需要实时绘制相应选择的路径
    • 根据相应的结果更新提示栏信息

    整理出基本的操作函数如下:

    //绘制初始的所有圆
    SignLock.prototype.drawCircle = function(){};
    
    //绘制触碰到的圆
    SignLock.prototype.drawTouchedCircle = function(i){};
    
    //连接当前触碰到的圆与前一个触碰到的圆圆心(绘制手势路径)
    SignLock.prototype.lineToTouchedCircle = function(i, j){};
    
    //连接最新碰到的圆与手势落点(并未实现该功能)
    SignLock.prototype.lineToTouchedPlace = function(x, y){};
    
    //更新提示栏信息
    SignLock.prototype.drawMessage = function(message){};
    
    //判断当前手的落点是否在圆内
    SignLock.prototype.isInCircle = function(x, y){};
    

    第三步,分析整个过程中的事件情况,主要有两类事件:模式选择事件(click)、手势事件(touchEvent)。

    • 模式选择事件(click)用于选择当前模式
    • 手势事件分成三种:touchstarttouchmovetouchend。其中touchstart表示开始触碰,需要初始化到stat1待输入状态;touchmove则需要实时的绘制手势路径与圆,并记录当前经过路径;touchend表示绘制结束,验证密码是否符合要求。

    事件绑定函数SignLock.prototype.bindEvent()代码大致如下所示:

    //添加触摸开始事件
    c.addEventListener("touchstart", function(e){
    //初始化代码
    }, false);
    
    //添加触碰移动事件
    c.addEventListener("touchmove", function(e){
    //绘制圆、路径等
    //记录相应信息
    }, false);
    
    //添加手离开屏幕事件
    c.addEventListener("touchend", function(e){
    //密码验证
    //提示信息更新
    }, false);
    
    //添加模式切换事件
    btn.addEventListener("click",function(){
    //模式选择,获取选择的模式
    },false);
    

    第四步,分析密码验证的过程,主要有密码设置验证与密码验证两个,函数如下:

    SignLock.prototype.checkPassword = function(pwd){};
    SignLock.prototype.validPassword = function(pwd, oldPwd){};
    

    其中返回消息的编码如下

    status message 含义
    0 密码正确/密码设置成功 success
    1 密码太短,至少需要5个点 failed
    2 请再次输入手势密码 falied
    3 两次输入的不一致 falied
    4 输入的密码不正确 failed

    第五步,由于密码设置错误后,需要回归最初状态,因此还需要reset进行重置。

    关键函数

    1. 绘制初始圆

    SignLock.prototype.drawCircle = function(){
        //获取canvas上下文
        var ctx = this.ctx;
        var circleCenterArr = this.circleCenterArr;
    
        var len = circleCenterArr.length;
    
        //设置颜色
        ctx.fillStyle = "#f8f8f8";
        ctx.beginPath();
        //根据圆的坐标绘制圆
        for(var i = 0; i < len; i++){
            ctx.moveTo(circleCenterArr[i][0], circleCenterArr[i][1]);
            ctx.arc( circleCenterArr[i][0], circleCenterArr[i][1], this.r, 0,Math.PI*2,true);
        }
    
        ctx.closePath();
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#bbbbbb";
        
        //填充圆圈以及边界
        ctx.stroke();
        ctx.fill();  
    };
    

    2. 设置密码与密码验证

    //判断密码是否正确
    SignLock.prototype.checkPassword = function(pwd){
        //初始化消息
        var result = {
            status: 4,
            message: "输入的密码不正确"
        }
        //获取实际密码
        var password = localStorage.getItem("password");
        //判断密码是否正确
        if(password == pwd.join("")){
            result.status = 0;
            result.message = "密码正确";
        }
        //this.touchedCircleArr = [];
        return result;
    };
    //判断密码设置是否符合规范
    SignLock.prototype.validPassword = function(pwd, oldPwd){
        var result = {
            status: 0,
            message: "密码设置成功"
        };
        if(pwd.length < 5){
            result.status = 1;
            result.message = "密码太短,至少需要5个点";
        }else if(oldPwd.length == 0){
            result.status = 2;
            result.message = "请再次输入手势密码";
        }else if(pwd.join("") != oldPwd.join("")){
            result.status = 3;
            result.message = "两次输入的不一致";
        }else {
            //密码正确则更新本地存储
            localStorage.setItem("password",pwd.join(""));
        }
        return result;
    }
    

    3. 事件绑定函数

    //绑定事件处理程序,主要有手势事件,以及radio的点击事件
    SignLock.prototype.bindEvent = function(){
        self = this;
        var c = this.c;
        var btn = this.btn;
    
        //添加触屏事件
        c.addEventListener("touchstart", function(e){
            //清空数据并初始化
            self.resetPic();
            //self.resetData();
        }, false);
        //添加触碰移动事件
        c.addEventListener("touchmove", function(e){
            //获取触点坐标
            var rect = e.currentTarget.getBoundingClientRect();
            var po = {
                x: e.touches[0].clientX - rect.left,
                y: e.touches[0].clientY - rect.top
            };
            var i = self.isInCircle(po.x, po.y);
            //划过圆圈是否记录
            if(i != 0 ){
                //如果未记录过,则画圆并记录
                if(self.touchedCircleArr.indexOf(i) == -1){
                    self.drawTouchedCircle(i);
                    var len = self.touchedCircleArr.length;
                    if(len >= 1){
                        self.lineToTouchedCircle(self.touchedCircleArr[len - 1],i);
                    }
                    self.touchedCircleArr.push(i);
                }
            }
        }, false);
        //添加手离开屏幕事件
        c.addEventListener("touchend", function(e){
            if(self.touchedCircleArr.length != 0){//防止意外触碰
                //判断密码是否符合
                var result = '';
                switch(self.model){
                    case 'set' :
                        result = self.validPassword(self.touchedCircleArr, self.oldPassword);
                    break;
                    case 'check':
                        result = self.checkPassword(self.touchedCircleArr);
                    break;
                }
                self.drawMessage(result);
            }
        }, false);
        //添加模式切换事件
        btn.addEventListener("click",function(){
            //重置界面和数据
            self.resetData();
            self.resetPic();
            var radio = document.getElementsByName("event");
            for(var i = 0; i < radio.length; i++){
                if(radio[i].checked){
                    self.model = radio[i].value;
                }
            }
        },false);
    }
    

    现存问题与改进计划

    1. 当手势过快的时候,会出现丢失点的情况。即快速划过1,2,3三个点,却只记录下来1,3两个点
    2. 在Chrome上测试通过,在Chrome Developer Tools测试兼容各种不同移动设备尺寸。但是样式在UC浏览器上会失效。由于时间有限,未能及时找到更改原因。但是可以参考自适应设计与响应式网页设计利用viewport来解实现
    3. 网页初次加载时,页面高度会高一些,页面刷新后即正常。原因暂时未知。
    4. 时间仓促,很多地方都没有优化好,先提交一个版本,等有时间了,再继续进行优化。

    参考文档

    1. MDN-Web技术文档 触摸事件
    2. CSS秘密花园:复杂背景图案
    3. 使用canvas来绘制图形
    4. 自适应设计与响应式网页设计
    5. H5手势解锁
  • 相关阅读:
    JavaScript
    关于setInterval()你所不知道的地方
    JavaScript面向对象和原型函数
    GET和POST有什么区别?及为什么网上的多数答案都是错的
    10个最常见的 HTML5 面试题及答案
    Ajax我选择这样入门
    前端应当了解的Web缓存知识
    JavaScript
    Linux rhel7 下MySQL5.7.18详细安装文档
    思科交换机配置DHCP的四个方面
  • 原文地址:https://www.cnblogs.com/omg-two/p/6733888.html
Copyright © 2011-2022 走看看