英文原文出自 Google Deveploers《Creating Fast Buttons for Mobile Web Applications》,由XiaoYi_HD翻译,并首发于 EsoftMobile.com。如需转载,请注明译者及出处信息。

背景

在 Google,我们不断地突破移动 Web 应用能够达到的效果,类似于 HTML5 这类技术让我们对原生应用和 Web 应用的界线开始变得模糊。为了这个目标,我们开发了一种新技术让纯 HTML 按钮能够有更快的响应速度。这之前,我们可能只是为按钮或者其他可以点击的元素增加点击处理,如:

<button onclick='signUp()'>Sign Up!</button>

使用这种方法存在一个问题就是,移动浏览器会在你点击按钮后 300ms 才触发事件,原因是浏览器需要区分你是否是要执行双击。但是对于大多数按钮,我们并不需要它处理双击事件,所以 300ms 的延时时间对于只是想执行点击事件的用户来说太长了。我们最早开发这种技术是在Google Voice mobile web app中,我们希望能够更加迅速的调用拨号事件。

处理触摸事件

该技术涉及一点 JavaScript 的东西来让按钮响应触摸(Touch)事件而不是点击(Click)事件。触摸事件响应不会有延时所以感受会比点击事件快很多,但是我们也需要考虑以下几个问题:

  1. 如果用户是点击屏幕上其他的元素而触发了按钮的触摸事件,这种情况我们不应该去执行按钮的事件。
  2. 如果用户按下按钮然后拖到屏幕其他位置而触发了触摸事件,我们也不应该执行按钮的事件。
  3. 我们希望按钮在按下的时间能够高亮来表示点击状态。

我们能够通过检测 touchstart 和 touchmove 事件来解决前两个问题,只需要考虑一个一开始在按钮上就是 touchstart 状态的触摸事件,而如果 touchstart 后存在了一个 touchmove,那我们就不应该处理 touchend 事件。

我们可以通过同时给按钮添加 onclick 处理来解决第三个问题,这样浏览器就会把它当成按钮并在点击时出现高亮。我们 touchend 处理也能保证按钮仍然很快响应,同时添加 onclick 可以在不支持触摸事件的浏览器上做为比较可靠的备用方案。

破坏讨厌的点击

在添加触摸事件的同时添加 onclick 事件又会带来另一个讨厌的问题,当你点击按钮时,点击 (click) 事件仍然会在 300ms 后执行,我们可以通过在 touchstart 事件里调用 preventDefault 来解决。在 touchstart 中调用 preventDefault 方法会会导致点击和滑动失效,但我们又想用户能够滑动视图即使一开始是点在按钮上,所以我们仍不能接受这种解决方案。接来下我们想出了一个被我们叫做点击破坏者(Click buster)的方案,我们给 body 添加一个点击事件监听(listener),当监听事件被触发,我们会区分点击是否由我们已经处理的 tap 事件导致的,如果这样,我们才调用 preventDefault 和 stopPropagation。

Fast Button Code

下面我们会提供一些我们实现这个想法的代码。

通过标签和事件创建一个 FastButton

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.onTouchEnd(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.element.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();
}
};

执行真正的点击事件并在 touchend 事件时避免讨厌的 click。

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, 移动距离在 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);
};

如果我们在给定的半径和时间内捕获到了点击事件,调用 stopPropagation 和 preventDefault。

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 库也提供了这种问题的解决方案,但是到目前为止我们没有发现有提供可靠备选方案和讨厌的点击问题。我们希望浏览器开发者能够在能够解决在不能缩放的页面上快速响应的问题,事实上我们已经在 Gingerbread 的浏览器上实现了。

测试代码FastButtonDemo已上传 github。

Posted by XiaoYi_HD - 6月 27 2013
如需转载,请注明: 本文来自 Esoft Mobile

为移动Web应用创建快速响应按钮的更多相关文章

  1. java web 工程创建及servlet简单使用

    1.java web工程创建 (1)File--->new--->project (2)选择java enterprise,按照下图操作 (3)点击next后,会进入如下界面,修改工程名后 ...

  2. [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序

    [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序 本节导读: 本节主要说明使用异步进行程序设计的优缺点及如何通过异步编程. 使用 ...

  3. Odoo 配置快速创建编辑按钮

    对于Man2one类型的数据,我们知道,form view中总会显示出一个尾巴似的"create and edit"和一个快速创建的机制,有时候业务人员一不小心就容易创建一个新的行 ...

  4. ServiceStack Web Service 创建与调用简单示列

    目录 ServiceStack 概念 ServiceStack Web Service 创建与调用简单示列 上篇文章介绍了ServiceStack是什么,本章进入主题,如何快速简单的搭建Service ...

  5. Web Api ——创建WebAPI

    方法在Win10 + VS2017(MVC5)测试通过 1.建立 WebApi项目: 选择菜单 “文件->新建醒目->web ->ASP.NET Web 应用程序” 输入项目名称和位 ...

  6. 用HTML5 Canvas为Web图形创建特效

    HTML5 Canvas 将使用像素在屏幕上绘制图形图像. 本节演示了五种用于操作像素以创建摄影特效的 Canvas 技术. 您可使用这些技术来生成独具特色的图像,为您的网站.博客.视频游戏画面.广告 ...

  7. 高性能网站优化-创建快速响应的Web

    <高性能网站建设进阶指南> 优化原则 优化的目的是希望降低程序的整体开销. 减少开销 通常认为开销就是程序的执行时间.而在进行优化工作时,应该把重点放在对程序开销影响最大的那部分. 假设我 ...

  8. Expression Blend创建自定义按钮

    在 Expression Blend 中,我们可以在美工板上绘制形状.路径和控件,然后修改其外观和行为,从而直观地设计应用程序.Button按钮也是Expression Blend最常用的控件之一,在 ...

  9. Web —— java web 项目 Tomcat 的配置 与 第一个web 项目创建

    目录: 0.前言 1.Tomcat的配置 2.第一个Web 项目 0.前言 刚刚开始接触web开发,了解的也不多,在这里记录一下我的第一个web项目启动的过程.网上教程很多,使用的java IDE 好 ...

随机推荐

  1. ASP.NET MVC 4 (一)路径映射

    原文:ASP.NET MVC 4 (一)路径映射 正如ASP.NET MVC名字所揭示的一样,是以模型-视图-控制设计模式构建在ASP.NET基础之上的WEB应用程序,我们需要创建相应的程序类来协调处 ...

  2. C++:类的组合

    在类中定义的数据成员一般都是基本数据类型或服复合数据类型.但是还可以根据需要使用 其他类的对象作为正在声明的数据成员.复杂的对象还可以有比较简单的对象一某种方式组合 而成,复杂对象和组成它的简单对象之 ...

  3. 计算机技能get(windows系统)

    1.快速打开程序,比如计算器,注册表,先按win键(不用再按win+r啦),输入程序名字,如calc,regedit等,直接打开. 2.自动左右分屏,win+上下左右方向键,win+↑ 最大化,win ...

  4. JBPM4 常用表结构

    JBPM4 常用表结构 第一部分:表结构说明 Jbpm4 共有18张表,如下,其中红色的表为经常使用的表   一:资源库与运行时表结构 1.  JBPM4_DEPLOYMENT 流程定义表 2.  J ...

  5. objectC时间用法

    #define kDEFAULT_DATE_TIME_FORMAT (@"yyyy-MM-dd HH:mm:ss") //获取当前日期,时间+(NSDate *)getCurren ...

  6. 【POJ】2170 Lattice Animals

    1. 题目描述给定$n \times m, n.m \in [1, 10]$的方格,求不同形状的$[1 \cdots 10]$联通块的个数?所谓不同形状,表示不能通过平移.旋转.镜像实现相同的形状.2 ...

  7. [Codeforces673C]Bear and Colors(枚举,暴力)

    题目链接:http://codeforces.com/contest/673/problem/C 题意:给一串数,不同大小的区间内出现次数最多的那个数在计数的时候会+1,问所有区间都这样计一次数,所有 ...

  8. bzoj2351 2462

    我没写hash,写了一些奇怪的做法,好像被hash随便操了…… 如果没有多测,那么这道题是白书上的例题 把询问矩阵当作a个模板串,建成一个ac自动机 把一开始的矩阵当作n个串放到自动机上匹配,找到a个 ...

  9. mybatis源码分析(1)——SqlSessionFactory实例的产生过程

    在使用mybatis框架时,第一步就需要产生SqlSessionFactory类的实例(相当于是产生连接池),通过调用SqlSessionFactoryBuilder类的实例的build方法来完成.下 ...

  10. UVa 10054 The Necklace【欧拉回路】

    题意:给出n个珠子,珠子颜色分为两半,分别用1到50之间的数字表示, 现在给出n个珠子分别的颜色,问是否能够串成一个环.即为首尾相连,成为一个回路 判断是否构成一个环,即判断是否为欧拉回路,只需要判断 ...