为移动端网页构造快速响应按钮

背景

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

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

 

处理触摸事件

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

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

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

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

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

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

消除幽灵点击

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

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 = [];

总结

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

本文转自:开源中国社区 [http://www.oschina.net]
本文标题:为移动端网页构造快速响应按钮
本文地址:http://www.oschina.net/translate/fast_buttons
参与翻译:tnjiny09lin

英文原文:Creating Fast Buttons for Mobile Web Applications

为移动端网页构造快速响应按钮,布布扣,bubuko.com

为移动端网页构造快速响应按钮

上一篇:Xcode升级5.1 iOS升级7.1无法真机调试


下一篇:Note_Master-Detail Application(iOS template)_01