爱心背景特效

总结

大概花了三天左右的时间,将这个 H5
的手势解锁给完成,自己还是比较满意的,虽然可能达不到评委老师的认可,不过自己在做的过程中,学习到了很多新知识。

HTML5实现屏幕手势解锁

2015/07/18 · HTML5 · 1
评论 ·
手势解锁

原文出处:
AlloyTeam   

效果展示

图片 1

实现原理 利用HTML5的canvas,将解锁的圈圈划出,利用touch事件解锁这些圈圈,直接看代码。

JavaScript

function createCircle() {//
创建解锁点的坐标,根据canvas的大小来平均分配半径 var n = chooseType;//
画出n*n的矩阵 lastPoint = []; arr = []; restPoint = []; r =
ctx.canvas.width / (2 + 4 * n);// 公式计算 半径和canvas的大小有关 for
(var i = 0 ; i < n ; i++) { for (var j = 0 ; j < n ; j++) {
arr.push({ x: j * 4 * r + 3 * r, y: i * 4 * r + 3 * r });
restPoint.push({ x: j * 4 * r + 3 * r, y: i * 4 * r + 3 * r }); }
} //return arr; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function createCircle() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径
 
        var n = chooseType;// 画出n*n的矩阵
        lastPoint = [];
        arr = [];
        restPoint = [];
        r = ctx.canvas.width / (2 + 4 * n);// 公式计算 半径和canvas的大小有关
        for (var i = 0 ; i < n ; i++) {
            for (var j = 0 ; j < n ; j++) {
                arr.push({
                    x: j * 4 * r + 3 * r,
                    y: i * 4 * r + 3 * r
                });
                restPoint.push({
                    x: j * 4 * r + 3 * r,
                    y: i * 4 * r + 3 * r
                });
            }
        }
        //return arr;
    }

canvas里的圆圈画好之后可以进行事件绑定

JavaScript

function bindEvent() { can.addEventListener(“touchstart”, function (e) {
var po = getPosition(e); console.log(po); for (var i = 0 ; i <
arr.length ; i++) { if (Math.abs(po.x – arr[i].x) < r &&
Math.abs(po.y – arr[i].y) < r) { // 用来判断起始点是否在圈圈内部
touchFlag = true; drawPoint(arr[i].x,arr[i].y);
lastPoint.push(arr[i]); restPoint.splice(i,1); break; } } }, false);
can.addEventListener(“touchmove”, function (e) { if (touchFlag) {
update(getPosition(e)); } }, false); can.addEventListener(“touchend”,
function (e) { if (touchFlag) { touchFlag = false; storePass(lastPoint);
setTimeout(function(){ init(); }, 300); } }, false); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function bindEvent() {
        can.addEventListener("touchstart", function (e) {
             var po = getPosition(e);
             console.log(po);
             for (var i = 0 ; i < arr.length ; i++) {
                if (Math.abs(po.x – arr[i].x) < r && Math.abs(po.y – arr[i].y) < r) { // 用来判断起始点是否在圈圈内部
 
                    touchFlag = true;
                    drawPoint(arr[i].x,arr[i].y);
                    lastPoint.push(arr[i]);
                    restPoint.splice(i,1);
                    break;
                }
             }
         }, false);
         can.addEventListener("touchmove", function (e) {
            if (touchFlag) {
                update(getPosition(e));
            }
         }, false);
         can.addEventListener("touchend", function (e) {
             if (touchFlag) {
                 touchFlag = false;
                 storePass(lastPoint);
                 setTimeout(function(){
 
                    init();
                }, 300);
             }
 
         }, false);
    }

接着到了最关键的步骤绘制解锁路径逻辑,通过touchmove事件的不断触发,调用canvas的moveTo方法和lineTo方法来画出折现,同时判断是否达到我们所画的圈圈里面,其中lastPoint保存正确的圈圈路径,restPoint保存全部圈圈去除正确路径之后剩余的。
Update方法:

JavaScript

function update(po) {// 核心变换方法在touchmove时候调用 ctx.clearRect(0,
0, ctx.canvas.width, ctx.canvas.height); for (var i = 0 ; i <
arr.length ; i++) { // 每帧先把面板画出来 drawCle(arr[i].x,
arr[i].y); } drawPoint(lastPoint);// 每帧花轨迹 drawLine(po ,
lastPoint);// 每帧画圆心 for (var i = 0 ; i < restPoint.length ; i++)
{ if (Math.abs(po.x – restPoint[i].x) < r && Math.abs(po.y –
restPoint[i].y) < r) { drawPoint(restPoint[i].x,
restPoint[i].y); lastPoint.push(restPoint[i]); restPoint.splice(i,
1); break; } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function update(po) {// 核心变换方法在touchmove时候调用
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
 
        for (var i = 0 ; i < arr.length ; i++) { // 每帧先把面板画出来
            drawCle(arr[i].x, arr[i].y);
        }
 
        drawPoint(lastPoint);// 每帧花轨迹
        drawLine(po , lastPoint);// 每帧画圆心
 
        for (var i = 0 ; i < restPoint.length ; i++) {
            if (Math.abs(po.x – restPoint[i].x) < r && Math.abs(po.y – restPoint[i].y) < r) {
                drawPoint(restPoint[i].x, restPoint[i].y);
                lastPoint.push(restPoint[i]);
                restPoint.splice(i, 1);
                break;
            }
        }
 
    }

最后就是收尾工作,把路径里面的lastPoint保存的数组变成密码存在localstorage里面,之后就用来处理解锁验证逻辑了

JavaScript

function storePass(psw) {// touchend结束之后对密码和状态的处理 if
(pswObj.step == 1) { if (checkPass(pswObj.fpassword, psw)) { pswObj.step
= 2; pswObj.spassword = psw; document.getElementById(‘title’).innerHTML
= ‘密码保存成功’; drawStatusPoint(‘#2CFF26’);
window.localStorage.setItem(‘passwordx’,
JSON.stringify(pswObj.spassword));
window.localStorage.setItem(‘chooseType’, chooseType); } else {
document.getElementById(‘title’).innerHTML = ‘两次不一致,重新输入’;
drawStatusPoint(‘red’); delete pswObj.step; } } else if (pswObj.step ==
2) { if (checkPass(pswObj.spassword, psw)) {
document.getElementById(‘title’).innerHTML = ‘解锁成功’;
drawStatusPoint(‘#2CFF26’); } else { drawStatusPoint(‘red’);
document.getElementById(‘title’).innerHTML = ‘解锁失败’; } } else {
pswObj.step = 1; pswObj.fpassword = psw;
document.getElementById(‘title’).innerHTML = ‘再次输入’; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function storePass(psw) {// touchend结束之后对密码和状态的处理
        if (pswObj.step == 1) {
            if (checkPass(pswObj.fpassword, psw)) {
                pswObj.step = 2;
                pswObj.spassword = psw;
                document.getElementById(‘title’).innerHTML = ‘密码保存成功’;
                drawStatusPoint(‘#2CFF26’);
                window.localStorage.setItem(‘passwordx’, JSON.stringify(pswObj.spassword));
                window.localStorage.setItem(‘chooseType’, chooseType);
            } else {
                document.getElementById(‘title’).innerHTML = ‘两次不一致,重新输入’;
                drawStatusPoint(‘red’);
                delete pswObj.step;
            }
        } else if (pswObj.step == 2) {
            if (checkPass(pswObj.spassword, psw)) {
                document.getElementById(‘title’).innerHTML = ‘解锁成功’;
                drawStatusPoint(‘#2CFF26’);
            } else {
                drawStatusPoint(‘red’);
                document.getElementById(‘title’).innerHTML = ‘解锁失败’;
            }
        } else {
            pswObj.step = 1;
            pswObj.fpassword = psw;
            document.getElementById(‘title’).innerHTML = ‘再次输入’;
        }
 
    }

解锁组件

将这个HTML5解锁写成了一个组件,放在

二维码体验: 图片 2

 

参考资料:

1 赞 4 收藏 1
评论

图片 3

<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>Happy Valentine’s Day everyone !</title>
</head>
<style>
body{
overflow: hidden;
margin: 0;
}
h1{
position: fixed;
top: 50%;
left: 0;
width: 100%;
text-align: center;
transform:translateY(-50%);
font-family: ‘Love Ya Like A Sister’, cursive;
font-size: 40px;
color: #c70012;
padding: 0 20px;
}
@media (min-width:1200px){
h1{
font-size: 60px;
}
}
</style>
<body>
<canvas></canvas>
<h1>canvas heart</h1>

4. 标记已画

前面已经说了,我们把已经 touch
的点(圆)放到数组中,这个时候需要将这些已经 touch
的点给标记一下,在圆心处画一个小实心圆:

JavaScript

drawPoints: function(){ for (var i = 0 ; i < this.touchCircles.length
; i++) { this.ctx.fillStyle = ‘#FFFFFF’; this.ctx.beginPath();
this.ctx.arc(this.touchCircles[i].x, this.touchCircles[i].y, this.r
/ 2, 0, Math.PI * 2, true); this.ctx.closePath(); this.ctx.fill(); } }

1
2
3
4
5
6
7
8
9
drawPoints: function(){
  for (var i = 0 ; i < this.touchCircles.length ; i++) {
    this.ctx.fillStyle = ‘#FFFFFF’;
    this.ctx.beginPath();
    this.ctx.arc(this.touchCircles[i].x, this.touchCircles[i].y, this.r / 2, 0, Math.PI * 2, true);
    this.ctx.closePath();
    this.ctx.fill();
  }
}

同时添加一个 reset 函数,当 touchend 的时候调用,400ms 调用 reset 重置
canvas。

到现在为止,一个 H5 手势解锁的简易版已经基本完成。

function onResize(){
ww = canvas.width = window.innerWidth;
wh = canvas.height = window.innerHeight;
}
ctx.strokeStyle = “red”;
ctx.shadowBlur = 25;
ctx.shadowColor = “hsla(0, 100%, 60%,0.5)”;
var precision = 100;
var hearts = [];
var mouseMoved = false;
function onMove(e){
mouseMoved = true;
if(e.type === “touchmove”){
hearts.push(new Heart(e.touches[0].clientX,
e.touches[0].clientY));
hearts.push(new Heart(e.touches[0].clientX,
e.touches[0].clientY));
}
else{
hearts.push(new Heart(e.clientX, e.clientY));
hearts.push(new Heart(e.clientX, e.clientY));
}
}
var Heart = function(x,y){
this.x = x || Math.random()*ww;
this.y = y || Math.random()*wh;
this.size = Math.random()*2 + 1;
this.shadowBlur = Math.random() * 10;
this.speedX = (Math.random()+0.2-0.6) * 8;
this.speedY = (Math.random()+0.2-0.6) * 8;
this.speedSize = Math.random()*0.05 + 0.01;
this.opacity = 1;
this.vertices = [];
for (var i = 0; i < precision; i++) {
var step = (i / precision – 0.5) * (Math.PI * 2);
var vector = {
x : (15 * Math.pow(Math.sin(step), 3)),
y : -(13 * Math.cos(step) – 5 * Math.cos(2 * step) – 2 * Math.cos(3
* step) – Math.cos(4 * step))
}
this.vertices.push(vector);
}
}
Heart.prototype.draw = function(){
this.size -= this.speedSize;
this.x += this.speedX;
this.y += this.speedY;
ctx.save();
ctx.translate(-1000,this.y);
ctx.scale(this.size, this.size);
ctx.beginPath();
for (var i = 0; i < precision; i++) {
var vector = this.vertices[i];
ctx.lineTo(vector.x, vector.y);
}
ctx.globalAlpha = this.size;
ctx.shadowBlur = Math.round((3 – this.size) * 10);
ctx.shadowColor = “hsla(0, 100%, 60%,0.5)”;
ctx.shadowOffsetX = this.x + 1000;
ctx.globalCompositeOperation = “screen”
ctx.closePath();
ctx.fill()
ctx.restore();
};

H5 手势解锁

扫码在线查看:

图片 4

或者点击查看手机版。

项目 GitHub
地址,H5HandLock。

首先,我要说明一下,对于这个项目,我是参考别人的,H5lock。

我觉得一个比较合理的解法应该是利用 canvas 来实现,不知道有没有大神用 css
来实现。如果纯用 css 的话,可以将连线先设置
display: none,当手指划过的时候,显示出来。光设置这些应该就非常麻烦吧。

之前了解过 canvas,但没有真正的写过,下面就来介绍我这几天学习 canvas
并实现 H5 手势解锁的过程。

var ww,wh;

准备及布局设置

我这里用了一个比较常规的做法:

(function(w){ var handLock = function(option){} handLock.prototype = {
init : function(){}, … } w.handLock = handLock; })(window) // 使用 new
handLock({ el: document.getElementById(‘id’), … }).init();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function(w){
  var handLock = function(option){}
 
  handLock.prototype = {
    init : function(){},
    …
  }
 
  w.handLock = handLock;
})(window)
 
// 使用
new handLock({
  el: document.getElementById(‘id’),
  …
}).init();

常规方法,比较易懂和操作,弊端就是,可以被随意的修改。

传入的参数中要包含一个 dom 对象,会在这个 dom 对象內创建一个
canvas。当然还有一些其他的 dom 参数,比如 message,info 等。

关于 css 的话,懒得去新建文件了,就直接內联了。

<script>
var canvas = document.querySelector(“canvas”),
ctx = canvas.getContext(“2d”);

3. 画折线

所谓的画折线,就是,将已经触摸到的点连起来,可以把它看作是画折线。

首先,要用两个数组,一个数组用于已经 touch 过的点,另一个数组用于存储未
touch 的点,然后在 move 监听时候,对 touch
的相对位置进行判断,如果触到点,就把该点从未 touch 移到 touch
中,然后,画折线,思路也很简单。

JavaScript

drawLine: function(p){ // 画折线 this.ctx.beginPath();
this.ctx.lineWidth = 3; this.ctx.moveTo(this.touchCircles[0].x,
this.touchCircles[0].y); for (var i = 1 ; i <
this.touchCircles.length ; i++) {
this.ctx.lineTo(this.touchCircles[i].x, this.touchCircles[i].y); }
this.ctx.lineTo(p.x, p.y); this.ctx.stroke(); this.ctx.closePath(); },

1
2
3
4
5
6
7
8
9
10
11
drawLine: function(p){ // 画折线
  this.ctx.beginPath();
  this.ctx.lineWidth = 3;
  this.ctx.moveTo(this.touchCircles[0].x, this.touchCircles[0].y);
  for (var i = 1 ; i < this.touchCircles.length ; i++) {
    this.ctx.lineTo(this.touchCircles[i].x, this.touchCircles[i].y);
  }
  this.ctx.lineTo(p.x, p.y);
  this.ctx.stroke();
  this.ctx.closePath();
},

JavaScript

judgePos: function(p){ // 判断 触点 是否在 circle 內 for(var i = 0; i
< this.restCircles.length; i++){ temp = this.restCircles[i];
if(Math.abs(p.x – temp.x) < r && Math.abs(p.y – temp.y) < r){
this.touchCircles.push(temp); this.restCircles.splice(i, 1);
this.touchFlag = true; break; } } }

1
2
3
4
5
6
7
8
9
10
11
judgePos: function(p){ // 判断 触点 是否在 circle 內
  for(var i = 0; i < this.restCircles.length; i++){
    temp = this.restCircles[i];
    if(Math.abs(p.x – temp.x) < r && Math.abs(p.y – temp.y) < r){
      this.touchCircles.push(temp);
      this.restCircles.splice(i, 1);
      this.touchFlag = true;
      break;
    }
  }
}

hearts.push(new Heart())
ctx.clearRect(0,0,ww,wh);
for (var i = 0; i < hearts.length; i++) {
hearts[i].draw();
if(hearts[i].size <= 0){
hearts.splice(i,1);
i–;
}
}
}
onResize();
window.addEventListener(“mousemove”, onMove);
window.addEventListener(“touchmove”, onMove);
window.addEventListener(“resize”, onResize);
requestAnimationFrame(render);
</script>
</body>
</html>

canvas

function render(a){
requestAnimationFrame(render);

优化 canvas 部分

对于 touchmove 函数,原理都是一样的,手指一划,就执行了 n
多次,这个问题后面在解决,先来看另一个问题。

touchmove
是一个高频函数,看到这里,如果你并没有仔细看我的代码,那你对我采用的
canvas 画图方式可能不太了解,下面这个是 touchmove 函数干了哪些事:

  1. 先判断,如果当前处于未选中一个密码状态,则继续监视当前的位置,直到选中第一个密码,进入第二步;
  2. 进入 update 函数,update
    函数主要干四件事,重绘圆(密码)、判断当前位置、重绘点、重绘线;

第二步是一个很揪心的动作,为什么每次都要重绘圆,点和线呢?

图片 5

上面这个图可以很好的说明问题,因为在设置或验证密码的过程中,我们需要用一条线来连接触点到当前的最后一个密码,并且当
touchmove 的时候,能看到它们在变化。这个功能很棒,可以勾勒出 touchmove
的轨迹。

但是,这就必须要时刻刷新 canvas,性能大大地降低,刷新的那可是整个
canvas。

因为 canvas
只有一个,既要画背景圆(密码),又要画已选密码的点,和折线。这其中好多步骤,自始至终只需要一次就好了,比如背景圆,只需在启动的时候画一次,已选密码,只要当
touchCircles
新加元素的时候才会用一次,还不用重绘,只要画就可以了。折线分成两部分,一部分是已选密码之间的连线,还有就是最后一个密码点到当前触点之间的连线。

如果有两个 canvas 就好了,一个存储静态的,一个专门用于重绘

为什么不可以有呢!

我的解决思路是,现在有两个
canvas,一个在底层,作为描绘静态的圆、点和折线,另一个在上层,一方面监听
touchmove
事件,另一方面不停地重绘最后一个密码点的圆心到当前触点之间的线。如果这样可以的话,touchmove
函数执行一次的效率大大提高。

插入第二个 canvas:

var canvas2 = canvas.cloneNode(canvas, true); canvas2.style.position =
‘absolute’;//让上层 canvas 覆盖底层 canvas canvas2.style.top = ‘0’;
canvas2.style.left = ‘0’; this.el.appendChild(canvas2); this.ctx2 =
canvas2.getContext(‘2d’);

1
2
3
4
5
6
var canvas2 = canvas.cloneNode(canvas, true);
canvas2.style.position = ‘absolute’;//让上层 canvas 覆盖底层 canvas
canvas2.style.top = ‘0’;
canvas2.style.left = ‘0’;
this.el.appendChild(canvas2);
this.ctx2 = canvas2.getContext(‘2d’);

要改换对第二个 ctx2 进行 touch 监听,并设置一个 this.reDraw
参数,表示有新的密码添加进来,需要对点和折线添加新内容, update
函数要改成这样:

update: function(p){ // 更新 touchmove this.judgePos(p); // 每次都要判断
this.drawLine2TouchPos(p); //
新加函数,用于绘最后一个密码点点圆心到触点之间的线 if(this.reDraw){ //
有新的密码加进来 this.reDraw = false; this.drawPoints(); // 添加新点
this.drawLine();// 添加新线 } },

1
2
3
4
5
6
7
8
9
update: function(p){ // 更新 touchmove
  this.judgePos(p); // 每次都要判断
  this.drawLine2TouchPos(p); // 新加函数,用于绘最后一个密码点点圆心到触点之间的线
  if(this.reDraw){ // 有新的密码加进来
    this.reDraw = false;
    this.drawPoints(); // 添加新点
    this.drawLine();// 添加新线
  }
},

drawLine2TouchPos: function(p){ var len = this.touchCircles.length;
if(len >= 1){ this.ctx2.clearRect(0, 0, this.width, this.width); //
先清空 this.ctx2.beginPath(); this.ctx2.lineWidth = 3;
this.ctx2.moveTo(this.touchCircles[len – 1].x, this.touchCircles[len

  • 1].y); this.ctx2.lineTo(p.x, p.y); this.ctx2.stroke();
    this.ctx2.closePath(); } },
1
2
3
4
5
6
7
8
9
10
11
12
drawLine2TouchPos: function(p){
  var len = this.touchCircles.length;
  if(len >= 1){
    this.ctx2.clearRect(0, 0, this.width, this.width); // 先清空
    this.ctx2.beginPath();
    this.ctx2.lineWidth = 3;
    this.ctx2.moveTo(this.touchCircles[len – 1].x, this.touchCircles[len – 1].y);
    this.ctx2.lineTo(p.x, p.y);
    this.ctx2.stroke();
    this.ctx2.closePath();
  }
},

相应的 drawPoints 和 drawLine
函数也要对应修改,由原理画所有的,到现在只需要画新加的。

效果怎么样:

图片 6

move 函数执行多次,而其他函数只有当新密码加进来的时候才执行一次。

加入节流函数

之前也已经说过了,这个 touchmove
函数执行的次数比较多,尽管我们已经用两个 canvas 对重绘做了很大的优化,但
touchmove 还是有点大开销。

这个时候我想到了防抖动和节流,首先防抖动肯定是不行的,万一我一直处于
touch
状态,重绘会延迟死的,这个时候节流会好一些。防抖和节流。

先写一个节流函数:

throttle: function(func, delay, mustRun){ var timer, startTime = new
Date(), self = this; return function(){ var curTime = new Date(), args =
arguments; clearTimeout(timer); if(curTime – startTime >= mustRun){
startTime = curTime; func.apply(self, args); }else{ timer =
setTimeout(function(){ func.apply(self, args); }, delay) } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
throttle: function(func, delay, mustRun){
  var timer, startTime = new Date(), self = this;
  return function(){
    var curTime = new Date(), args = arguments;
    clearTimeout(timer);
    if(curTime – startTime >= mustRun){
      startTime = curTime;
      func.apply(self, args);
    }else{
      timer = setTimeout(function(){
        func.apply(self, args);
      }, delay)
    }
  }
}

节流函数的意思:在延迟为 delay
的时间内,如果函数再次触发,则重新计时,这个功能和防抖动是一样的,第三个参数
mustRun 是一个时间间隔,表示在时间间隔大于 mustRun
后的一个函数可以立即直接执行。

然后对 touchmove 的回调函数进行改造:

var t = this.throttle(function(e){ e.preventDefault ? e.preventDefault()
: null; e.stopPropagation ? e.stopPropagation() : null; var p =
this.getTouchPos(e); if(this.touchFlag){ this.update(p); }else{
this.judgePos(p); } }, 16, 16)
this.canvas2.addEventListener(‘touchmove’, t, false)

1
2
3
4
5
6
7
8
9
10
11
var t = this.throttle(function(e){
  e.preventDefault ? e.preventDefault() : null;
  e.stopPropagation ? e.stopPropagation() : null;
  var p = this.getTouchPos(e);
  if(this.touchFlag){
    this.update(p);
  }else{
    this.judgePos(p);
  }
}, 16, 16)
this.canvas2.addEventListener(‘touchmove’, t, false)

关于 delay 和 mustRun 的时间间隔问题,web 性能里有一个 16ms
的概念,就是说如果要达到每秒 60 帧,间隔为 1000/60 大约为 16
ms。如果间隔大于 16ms 则 fps 会比 60 低。

鉴于此,我们这里将 delay 和 mustRun 都设为
16,在极端的情况下,也就是最坏的情况下,或许需要 15 + 15 = 30ms
才会执行一次,这个时候要设置两个 8
才合理,不过考虑到手指活动是一个连续的过程,怎么可能会每 15
秒执行一次,经过在线测试,发现设置成 16 效果还不错。

性能真的能优化吗,我们来看两个图片,do 和 wantdo
表示真实执行和放到节流函数中排队准备执行。

当 touchmove 速度一般或很快的时候:

图片 7

当 touchmove 速度很慢的时候:

图片 8

可以看出来,滑动过程中,速度一般和快速,平均优化了一半,慢速效果也优化了
20 到 30%
之间,平时手势锁解锁时候,肯定速度很快。可见,节流的优化还是很明显的。

关键是,优化之后的流程性,没有受到任何影响。

这个节流函数最终还是出现了一个 bug:由于是延迟执行的,导致
e.preventDefault
失效,在手机浏览器向下滑会出现刷新的情况,这也算事件延迟的一个危害吧。

解决办法:在节流函数提前取消默认事件:

throttle: function(func, delay, mustRun){ var timer, startTime = new
Date(), self = this; return function(e){ if(e){ e.preventDefault ?
e.preventDefault() : null; //提前取消默认事件,不要等到 setTimeout
e.stopPropagation ? e.stopPropagation() : null; } … } }

1
2
3
4
5
6
7
8
9
10
throttle: function(func, delay, mustRun){
  var timer, startTime = new Date(), self = this;
  return function(e){
    if(e){
      e.preventDefault ? e.preventDefault() : null; //提前取消默认事件,不要等到 setTimeout
      e.stopPropagation ? e.stopPropagation() : null;
    }
    …
  }
}

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website