为移动端网页构造快速响应按钮 已翻译 100%

kenzone 投递于 2013/11/06 13:41 (共 6 段, 翻译完成于 11-09)
阅读 3097
收藏 79
8
加载中

背景

在谷歌,我们不断地推测手机网页应用的可能性。像HTML5这样的技术使我们网页版的应用以及运行在手机设备上的原生应用。而这些技术的成就之一就是我们开发了一种新的创建按钮的方法,使按钮的响应时间远远快于一般的HTML按钮。在此之前的按钮或者其他响应事件,我们可能会设计一个点击事件。例如:

<button onclick='signUp()'>Sign Up!</button>
这种方法的问题是,当你开始点击按钮开启点击事件时,浏览器会停留大约300毫秒的时间。这是因为浏览器在等待,看你是否双击按钮。对于大多数的按钮,我们在开发的时候就知道不会执行双击事件,所以点击后等待的这段时间是在浪费用户的时间。我们在Google Voice手机网页应用上第一次使用这种技术,目的是想让用户拨号时有更快的相应速度。
y09lin
y09lin
翻译于 2013/11/06 21:41
3

处理触摸事件

这个技术涉及到一点javascript,允许按钮对touchEnd事件响应而不是click事件。touchEnd事件的触发是没有延迟的,所以能够明显的比click事件要快,但是仍有一些问题值得考虑:

1.如果用户轻触了屏幕的某个地方然后引起了一个按钮的touchEnd事件,而我们不应该由此触发一个click事件。

2.如果用户按下了按钮,然后在屏幕上拖动了一段距离,然后引起按钮的touchEnd事件,此时我们也不应该触发click事件。

3.我们希望当用户按下按钮时,能够给这个按钮一个按下的状态,从而使得其突出显示。

tnjin
tnjin
翻译于 2013/11/09 19:05
3

我们能够通过监听touchStart和touchMove事件解决前两个问题。如果在按钮上之前有touchStart事件,那么我们才会考虑在按钮上的touchEnd事件。同样,如果有一个touchMove事件且同touchStart的位置相比移动超过了某个阈值,那么我们就不应该把这个touchEnd事件当做click事件来处理。

我们也可以通过给按钮添加一个onclick处理函数来解决第三个问题。那么做会恰好让浏览器于把他当做按钮,而我们的touchEnd处理函数仍能够确保这个按钮响应很快。同样,一个onclick处理函数的存在,也能让那些不支持touch事件的浏览器优雅降级。

tnjin
tnjin
翻译于 2013/11/09 19:22
3

消除幽灵点击

重新添加onclick处理函数给按钮,会引发最后一个令人讨厌的问题。但你轻触按钮时,一个click事件仍然会在300ms后被触发。现在这个click处理函数就有被运行两次的危险。这个可以通过在touchStart事件中调用preventDefault 很容易被解决。在touchStart事件中调用preventDefault方法将会阻止当前的轻触所引发的的click和scrolling。我们希望用户可以滚动页面,即使他们从按钮的位置开始滚动,所以我们不认为这是一个可接受的解决方案。我们想出的能解决幽灵点击的方法叫做click buster(点击破坏者)。我们所做的只是在页面body中添加一个click的监听器,在捕获阶段监听。当我们的监听器被触发,我们就会尝试判定这个click事件是不是我们已经当做tap事件来处理的结果。如果是的话,我们就可以调用preventDefault和stopPropagation来阻止他。

tnjin
tnjin
翻译于 2013/11/09 19:41
2

Fast Button代码

我们将提供一些代码来实现我们刚刚讨论过的想法。

引用元素和click-handler来构建FasrButton。

google.ui.FastButton = function(element, handler) {
  this.element = element;
  this.handler = handler;

  element.addEventListener('touchstart', this, false);
  element.addEventListener('click', this, false);
};

google.ui.FastButton.prototype.handleEvent = function(event) {
  switch (event.type) {
    case 'touchstart': this.onTouchStart(event); break;
    case 'touchmove': this.onTouchMove(event); break;
    case 'touchend': this.onClick(event); break;
    case 'click': this.onClick(event); break;
  }
};
保留对touchStart位置的引用,然后开始监听touchMove和touchEnd事件。调用stopPropagation来保证另一个动作不会再次处理同样的点击事件。
google.ui.FastButton.prototype.onTouchStart = function(event) {
  event.stopPropagation();

  this.element.addEventListener('touchend', this, false);
  document.body.addEventListener('touchmove', this, false);

  this.startX = event.touches[0].clientX;
  this.startY = event.touches[0].clientY;
};
当一个touchMove事件被触发,检查用户是否推动超过10px这个阈值。
google.ui.FastButton.prototype.onTouchMove = function(event) {
  if (Math.abs(event.touches[0].clientX - this.startX) > 10 ||
      Math.abs(event.touches[0].clientY - this.startY) > 10) {
    this.reset();
  }
};
触发一个实际的click处理函数,如果有touchEnd事件,就阻止幽灵点击事件。
google.ui.FastButton.prototype.onClick = function(event) {
  event.stopPropagation();
  this.reset();
  this.handler(event);

  if (event.type == 'touchend') {
    google.clickbuster.preventGhostClick(this.startX, this.startY);
  }
};

google.ui.FastButton.prototype.reset = function() {
  this.element.removeEventListener('touchend', this, false);
  document.body.removeEventListener('touchmove', this, false);
};
调用preventGhostClick来消除掉所有的在2.5s内且在不超过保留的x,y坐标周围25px的点击事件。
google.clickbuster.preventGhostClick = function(x, y) {
  google.clickbuster.coordinates.push(x, y);
  window.setTimeout(google.clickbuster.pop, 2500);
};

google.clickbuster.pop = function() {
  google.clickbuster.coordinates.splice(0, 2);
};
如果我们 在给定的范围和时间阈值里捕捉到一个click事件,我们调用stopPropagation和preventDefault。调用preventDefault能够阻止链接变为activated状态。
google.clickbuster.onClick = function(event) {
  for (var i = 0; i < google.clickbuster.coordinates.length; i += 2) {
    var x = google.clickbuster.coordinates[i];
    var y = google.clickbuster.coordinates[i + 1];
    if (Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
      event.stopPropagation();
      event.preventDefault();
    }
  }
};

document.addEventListener('click', google.clickbuster.onClick, true);
google.clickbuster.coordinates = [];
tnjin
tnjin
翻译于 2013/11/09 19:56
3

总结

基于这一点,你应该很容易就可以创建快速响应的按钮。通过一些奇特的方式,你能够使这些按钮看起来像是基于你的开发平台的本地按钮一样。已经有一些解决同样问题的移动javascript库可以使用了,但是我们还从未见过任何一个能够提供click事件的优雅降级或者幽灵点击事件的解决方案的js库。我们希望浏览器的开发者们能够在将来的版本中,通过当网站的缩放被禁止(通过使用viewport的meta标签)时,能直接触发click事件的方式解决这个问题。实际上,这已经是姜饼版安卓浏览器要解决的事情了。

tnjin
tnjin
翻译于 2013/11/09 20:08
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(13)

开源中国最帅没有之一
开源中国最帅没有之一

引用来自“onemade”的评论

https://github.com/ftlabs/fastclick

嗯 谢谢
onemade
onemade
https://github.com/ftlabs/fastclick
tnjin
tnjin

引用来自“EREHMii”的评论

引用来自“tnjin”的评论

为毛我翻译的就没人看呢?

太小众的原因吧....

谢谢
任意球
任意球
来支持一下咯
王洪旭
王洪旭
mark
有初啊
有初啊

引用来自“tnjin”的评论

为毛我翻译的就没人看呢?

太小众的原因吧....
听风者
听风者
细节东西 不错。
浩浩好好
浩浩好好
不错的文章
徐迎龙
徐迎龙
不错
qqli
qqli
来看看
返回顶部
顶部