热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

内部HybridApp经验解读

四个解读:click事件还是tap事件?Zepto的showhide有时不靠谱。Android下的跨域问题。pushState调用


郑昀编纂 关键词:Hybrid,Zepto,Fastclick,Backbone,sui,SPA,pushState,跨域,CORS


  1. click 事件还是 tap 事件?

  2. Zepto 的 show/hide 有时不靠谱

  3. Android 下的跨域问题

  4. pushState 调用失败也属于跨域问题




   内部做 Hybrid App 开发历程也不短了,杨海波、潘军和刘勤红与前端组、App 组一起总结了不少宝贵的经验教训,逐步形成我们自己的标准打法。下面选了几个经验点(坑)做进一步解读。

 


0x00,click 事件还是 tap 事件?

300 毫秒点击延迟的来龙去脉一文所言『尽管苹果公司创造的双击缩放行为,是一种在移动设备上访问桌面端站点的不错的解决方案,但随之引入的 300 毫秒点击延迟也成为了移动端网站让用户感觉卡顿的罪魁祸首之一』,此文把原因和对策讲得清楚透彻,此处郑昀不再赘述,感兴趣的同学自习一下。

 

那么,我们看到,时至今日,有三种应对措施:


  1. 对于无需缩放的页面,禁用双击缩放功能,

  2. 引入 Zepto 框架的 tap 事件


    • Zepto 趁着 JQuery 在移动互联网市场历史包袱重的机会,搞了一套轻量级类 JQuery 框架的代码,核心代码千行,从而迅速成为移动端 DOM 操作库的首选。

    • Zepto 提供了一个 touch 库,在载入 Zepto 后为 document 绑定 touchstart、touchmove、touchend 事件,根据手指 x、y 值的位置,判断方向从而触发 tap、doubleTap、swipeLeft 等事件。

    • 原本没有 tap 事件,Zepto tap 是用 touchstart 和 touchend 模拟出来的。


  3. 引入 Fastclick 的 click 事件


    • FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick 在检测到 touchend 事件的时候,会通过 DOM 自定义事件立即触发一个模拟click 事件,并把浏览器在 300 毫秒之后真正触发的 click 事件阻止掉。



 

但我们在实践过程中,也领教了著名的 Zepto tap 『点透』坑

对此,yexiaochai 分析道:


1,一旦引入 touch 库便会在全局绑定事件,每次点击皆会触发无意义的 tap 事件 ;

2,zepto 为了实现 doubleTap 等功能,2B 地在 touchend 上设置了一个 setTimeout,然后整个世界都充满了翔了。

由于 setTimeout 的抛出主干流程,导致其 event 参数失效,这个时候就算在 tap 事件函数中执行 e.preventDefault() 或者什么都是无效的,这是导致 zepto tap“点透”的罪魁祸首。


点透的效果可以看 http://www.cnblogs.com/lilyimage/p/3740668.html 所述。总之,有人建议,如果你还打算继续用 Zepto,那么它的 tap 事件已经没用了,那你可以自己 build 一个无 touch 模块的 Zepto,以便减小文件大小并提高运行效率。


Fastclick 是怎么做的呢?

Fastclick 将事件绑定到你传入的元素 上,在 touchstart 和 touchend 后(会手动获取当前点击 el),如果是类 click 事件便手动触发 dom 元素的 click 事件。所以 click 事件在 touchend 便被触发,于是整个响应速度就起来了。这里虽然使用了 touch 事件,但 touch 事件是绑定到了具体 dom 而不是 document 上 ,所以 e.preventDefault 是有效的,我们可以阻止冒泡,也可以阻止浏览器默认事件。

 

最终我们采用 Fastclick 的 click 事件来规避点击延迟响应。

 


0x01,Zepto 的 show/hide 有时不靠谱

在 Hybrid App 开发初期,我们引入了 Zepto 的 fx_methods 模块,来控制元素的显示与隐藏:









fx_methods Animated showhidetoggle, and fade*() methods.



技术分享


但总是出现一些莫名奇妙的问题,如元素不能正常显示,元素的定位发生变化等,非常不好定位,最终前端同学发现是 Zepto 的 show/hide 造成的。

对此,我们可以找到 2012 年的一个 issue 佐证:












fx_methods show() and hide() add unnecessary CSS properties on non-animated DOM nodes


When you add fx_methods to your Zepto, the show() and hide() methods are overriden with methods that also call animate. 

Even in the case of undefined speed (normal show), animate still adds many CSS properties to the shown/hidden nodes.

These unexpected CSS rules can interfere with the page CSS (in my case, it has changed the positioning of my child fixed DIVs).



即,她认为,即使是简单的显示,fx_methods.js 的 show/hide 也会加入一些额外的 CSS,以至于影响整个页面样式,而且还会乱弹琴地改变透明度,重置为 1.0。samwu 在 2013 年也讲过类似问题。

所以,我们有两种选择:


  1. 继续引入 Zepto 的 fx_methods,但按 madrobby 所说,没有定义 speed 时,仅调用原生的 show;


    • 从 Zepto 官方的 技术分享技术分享 改为 技术分享技术分享


  2. 如 0x00 和本小节所描述的问题,不要引入 Zepto 的 touch 和 fx_methods 模块


    • 只引入 zepto+event+ajax+form+ie 基本模块



 

0x02,Android 下的跨域问题

在 Hyrbid App 里,郑昀要求采用 Template+Data=HTML 模式在手机客户端本地渲染出所需的页面。

Template(HTML5 模板文件+JS+CSS+Images)既可以提前打包到 App 安装包里,也可以从 CDN(如无,则溯源到静态文件服务器)拉到客户端里并存储在本地。

Data 则是通过模板文件里的 Javascript 脚本,从远端拉取 JSON 格式的数据包。

那么,这里存在一个跨域问题:



  • Android 的 WebView 通过 file:// 协议加载本地的 HTML5 模板文件。本地文件的 JS 向远端发送 AJAX 请求,受到同源策略的限制,譬如你可能会看到“XMLHttpRequest cannot load file://…… Origin null is not allowed by Access-Control-Allow-Origin.”的错误提示,即当你的 URI 是 file:// 时,源域名(origin)为空。


    • 借用 difcareer 的评论:Web 应用程序能且只能使用 XMLHttpRequest 对象向其加载的源域名发起请求,而不能向任何其他域名发起请求,但 HTML5 允许 AJAX 跨域向其他域名发起请求,但是不能获取服务器端响应


  • iOS 下无此跨域问题。





 

对此,大致有四种应对措施:



  • 如果是 GET 请求:


    1. 可以通过 JSONP 来解决跨域问题;


  • 如果是 POST 请求:



  1. 由 App 原生代码发起网络操作,成功后回调 JS。

  2. 利用 HTML5 的“Cross-Origin Resource Sharing(CORS,跨域资源共享)”新特性,在服务器端响应头里设置:Access-Control-Allow-Origin 头域;


    • 不限制来源,Access-Control-Allow-Origin: *

    • 限制来源域,Access-Control-Allow-Origin: http://xxx.com

    • 具体设置参考 http://enable-cors.org/;

    • 这需要浏览器支持;

    • SmdCn 提及,『在某些版本的 Android 浏览器中,因为缓存的原因,第一次 CORS 正常,但第二次会失效。对此,可以通过在响应头中增加 Cache-Control: no-cache 来解决』。



  3. 设置 Android 的 WebView 如下 settings 参数为 True:

    if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){

        webView.getSettings().setAllowUniversalAccessFromFileURLs(true);

    }

    由此允许通过 file url 加载的 Javascript 可以访问其他的源,包括其他的文件和 http/https 等源。这个设置在 JELLY_BEAN 以前的版本默认是允许,在 JELLY_BEAN 及以后的版本中默认是禁止的。

    According to the documentation for setAllowFileAccessFromFileURLs and setAllowUniversalAccessFromFileURLs, they used to be set to true for ICS and older. Starting in JellyBean they turned it off. If you are trying to load a local JS file from a local HTML page, then you‘ll need to enable these. – Steven




 



我们是既会在 Native API 里封装了一个接口 sendpostmsg,让 JS 调用(但也因此导致『除了 POST 请求,其他都可以在 PC 浏览器调试』),也会使用 setAllowUniversalAccessFromFileURLs 方法。

 


0x03,pushState 调用失败也属于跨域问题

我们需要使用 HTML5 的特性 history.pushState,手动插入历史记录和修改地址栏,这样虽然地址栏被修改了,但并不触发网页跳转。

同上节,本地文件的 JS 调用 history.pushState 也会遇到跨域问题,报错如下图所示:

技术分享


技术分享

原因仍是当你的 URI 是 file:// 时,源域名(origin)为空。

由于我们使用了 SUI,绕不开这个问题。所以,最终还是得调用 webView.getSettings().setAllowUniversalAccessFromFileURLs(true);

彻底解决各种跨域问题。

 

参考资源:

1,2014,300 毫秒点击延迟的来龙去脉

2,2015,freebuf,鸢尾,同源策略详解及绕过(Part1);

3,2015,知乎,纯数据 API 服务,设置 Access-Control-Allow-Origin: * 是否会有安全性隐患?

4,2012,csdn,CORS(跨域资源共享)简介;

5,2014,smdcn,使用HTML5 CORS特性进行Ajax跨域POST请求;

6,2011,sof,WebView Javascript cross domain from a local HTML file

7,2014,龚广,WebView跨源攻击分析;


欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注:

技术分享

转载时请注明“转载自旁观者-博客园”或者给出本文的原始链接。


-EOF-


推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 人脸检测 pyqt+opencv+dlib
    一、实验目标绘制PyQT界面,调用摄像头显示人脸信息。在界面中,用户通过点击不同的按键可以实现多种功能:打开和关闭摄像头, ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了10分钟了解Android的事件分发相关的知识,希望对你有一定的参考价值。什么是事件分发?大家 ... [详细]
author-avatar
特贰的大妞
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有