说明
2017 前端星计划选拔作业学习笔记
源码笔记:https://github.com/kaimo313/h5-handlelock
原型和操作流程
用户用手指按顺序依次划过 9 个原点中的若干个(必须不少于 4 个点),如果划过的点的数量和顺序与之前用户设置的相同,那么当用户的手指离开屏幕时,判定为密码输入正确,否则密码错误。
要求:实现一个移动网页,允许用户设置手势密码和验证手势密码。已设置的密码记录在本地 localStorage 中。
stat 1:设置密码。
用户选择设置密码时,要提示用户输入手势密码。
stat 2:密码长度太短
如果用户输入的密码不足 5 个点,提示用户密码太短。
stat 3:再次输入密码
设置成功一次密码后,提示用户再次输入密码。
stat 4:两次密码输入不一致
如果用户输入的两次密码不一致,提示并重置,重新开始设置密码
stat 5:密码设置成功
如果两次输入一致,密码设置成功,更新 localStorage。
stat 6:验证密码 - 不正确
切换单选框进入验证密码模式,将用户输入的密码与保存的密码相比较,如果不一致,则提示输入密码不正确,重置为等待用户输入。
stat 7:验证密码 - 正确
如果用户输入的密码与 localStorage 中保存的密码一致,则提示密码正确。
组件设计步骤
组件设计一般来说包括 7 个步骤,分别是:理解需求、技术选型、结构(UI)设计、数据和 API 设计、流程设计、兼容性和细节优化,以及工具和工程化。
理解需求
需要由使用者决定设置密码的过程里执行什么操作、验证密码的过程和密码验证成功后执行什么操作,应当将过程节点开放出来,让使用者来决定。
技术选型
UI 展现的核心是九宫格和选中的小圆点,这里我们使用 canvas 去实现效果
SVG 原生操作的 API 不是很方便,可以使用Snap.svg,但移动端兼容性不如 DOM 和 Canvas 好
DOM 的优点是容易实现响应式,事件处理简单,布局也不复杂,但是要计算斜线的长度和斜率。
第一个细节:用 DOM 构造一个正方形的容器,使用 padding-top:100% 撑开容器高度使它等于容器宽度。
#container { position: relative; overflow: hidden; width: 100%; padding-top: 100%; height: 0px; background-color: white; }
第二个细节:为了在 retina 屏上获得清晰的显示效果,可以将 Canvas 的宽高增加一倍,然后通过 transform: scale(0.5)
来缩小到匹配容器宽高。
#container canvas{ position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0.5); }
Retina:一种新型高分辨率的显示标准,是把更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度。由摩托罗拉公司研发。最初该技术是用于Moto Aura上。这种分辨率在正常观看距离下足以使人肉眼无法分辨其中的单独像素。也被称为视网膜显示屏。
原因:canvas 绘制的图形是位图,即栅格图像或点阵图像,当将它渲染到高清屏时,会被放大,每个像素点会用 devicePixelRatio 的平方个物理像素点来渲染,因此图片会变得模糊。
另外设置一下canvas的宽高相等
let width = 2 * container.getBoundingClientRect().width; canvas.width = canvas.height = width;
这样就得到了一个正方形
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>kaimo canvas demo</title> <style> #container { position: relative; overflow: hidden; width: 100%; padding-top: 100%; height: 0px; background-color: white; } #container canvas{ position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0.5); } </style> </head> <body> <div id="container"> <canvas id="canvas"></canvas> </div> <script> let width = 2 * container.getBoundingClientRect().width; canvas.width = canvas.height = width; </script> </body> </html>
结构设计
因为 Canvas 的渲染机制里,要更新画布的内容,需要刷新要更新的区域重新绘制。因此我们有必要把频繁变化的内容和基本不变的内容分层管理,这样能显著提升性能。
这里我们可以分成三层
- 底层:已经画好的线
- 中层:排列的九个点
- 上层:随着手指头移动的那个线段
下面确定圆点的位置:我们使用 4 x 4 的这种,需要遍历绘制实心圆,另外 Touch 相对于屏幕的坐标也需要转换为 Canvas 相对于画布的坐标。
API 设计
Recorder 只负责记录用户手势行为
- render:进行渲染
- record:负责记录
- clearPath:负责在画布上清除上一次记录的结果
- cancel:负责终止记录过程
对于输出结果,可以使用选中圆点的行列坐标拼接起来得到一个唯一的序列。
例如:11121323
就是如下选择图形:
让 Locker 继承 Recorder,管理实际的设置和验证密码的过程
- check:负责校验
- update:负责更新密码
另外我们可以将外观配置抽取出来:比如颜色,个数等等。
流程设计
验证密码的流程:
设置密码的流程:
打包组件
这里我们采用 rollup 进行组件的打包,rollup 它是一个类似于 webpack 的打包工具,区别于 webpack,它更适合一个库的打包。
核心概念
input:入口文件,类比于 webpack 的 entry,它指明了我们库文件入口位置。
output:输出位置,它指明了打包后的输出信息,包括:输出目录,打包文件名等。
plugins:插件,rollup 在构建过程中,插件可提供一些辅助功能,例如:alias别名解析、转义ES6等。
external:当我们的库依赖于其它第三方库时,我们不需要把这些第三方库一起打包,而是应该把依赖写在external里面。
构建说明
umd:此选项构建出来的库文件是一个通用模式,可以通过不同的方式去使用:script 标签引入,ES Module 规范引入和 CommonJs 规范引入等。
cjs:此选项构建出来的库文件主要为 CommonJs 规范,可在 Node 环境中使用。
es:此版本构建出来的库文件主要为 ES Module 规范,可在支持 ES Module 也就是 import/export 的环境中使用。
在 package.json 中配置打包命令:
{ "scripts": { "dev": "rollup -wc" } }
-c
:为--config
的缩写,表示设置 rollup 打包的配置。-w
:为--watch
的缩写,在本地开发环境添加-w
参数可以监控源文件的变化,自动重新打包。
常用插件