honglio

honglio 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

honglio 赞了文章 · 2015-12-05

JS常用库解密-FastClick

众所周知,移动端在处理点击事件的时候,会有300毫秒的延迟。恰恰是这300毫秒的延迟,会让人有一种卡顿的体验。

这300毫秒的原因,在于早期浏览器的实现中,浏览器不知道用户触摸后,到底想做什么,所以故意等待300毫秒,再触发click事件。

既然我们已经知道了原因了,怎么解决呢?

方案1-粗暴治标法

因为浏览器对click事件的处理,有300ms的延迟,而touchstart几乎是立即执行的,估将所有click事件的监听,改为touchstart事件的监听,即可消除这300ms的延迟。

但这样副作用也很大,移动端的交互体验全靠触摸,touchstart将会干扰其他交互行为的处理,例如滚动、拖拽等。

方案2-模拟修复法

既然浏览器有这300ms的延迟,那么我们来代替浏览器判断,手动触发click事件,这也是fastClick的解决方案。

fastClick的核心代码

FastClick.prototype.onTouchEnd = function(event){

  // 一些状态监测代码 

  // 从这里开始,
  if (!this.needsClick(targetElement)) {
    // 如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click
    event.preventDefault(); 
    // 触发一次模拟的click
    this.sendClick(targetElement, event);
  }
}

这里可以看到,FastClick在touchEnd的时候,在符合条件的情况下,主动触发了click事件,这样避免了浏览器默认的300毫秒等待判断。为了防止原生的click被触发,这里还通过event.preventDefault()屏蔽了原生的click事件。

我们来看看他是怎么模拟click事件的

FastClick.prototype.sendClick = function(targetElement, event) {

  // 这里是一些状态检查逻辑

  // 创建一个鼠标事件
  clickEvent = document.createEvent('MouseEvents');
  // 初始化鼠标事件为click事件
  clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);

  // fastclick的内部变量,用来识别click事件是原生还是模拟
  clickEvent.forwardedTouchEvent = true;

  // 在目标元素上触发该鼠标事件,
  targetElement.dispatchEvent(clickEvent);

我们在网上搜索fastClick,大部分都在说他解决了zepto的点击穿透问题,他是怎么解决的呢?就是上面最后一句,他模拟的click事件是在touchEnd获取的真实元素上触发的,而不是通过坐标计算出来的元素。

最后,原理虽简单,但还是建议大家直接用FastClick而不是自己再实现一个。因为,你看他源码里面的注释,有很多特殊情况的补丁的,自己实现一个精简版难免会漏这漏那。

附录

同步发表于我的博客

查看原文

赞 3 收藏 50 评论 0

honglio 提出了问题 · 2015-11-19

解决原生app嵌入h5页面,怎么实现不升级app更新H5页面的CSS

H5页面为了离线浏览已经把CSS都放在asset文件夹下了。现在想不安装新的原生安装包,更新CSS文件,应该怎么做?请这方面有经验的朋友多给出几种解决方案,并分别列出优劣。

关注 6 回答 4

honglio 回答了问题 · 2015-11-18

解决JS计算元素的距离

$('#element').offset().top-$(window).scrollTop();

Demo

关注 3 回答 3

honglio 回答了问题 · 2015-11-18

求一个华丽丽的html5/css幻灯片框架

www.presentbook.cn
H5在线幻灯片编辑放映平台

关注 4 回答 11

honglio 回答了问题 · 2015-11-18

解决请问各位大神,可以用HTML5和javascript和css来开发一款app吗?

混合型App是用原生App嵌套Web页面开发的应用。混合型App可以在App 商店下载并被安装。与原生应用相比,主要用户界面和业务逻辑都是用Web技术也就是HTML+CSS+Javascript实现的;它是用原生Web view控制器中嵌入Web网页,且没有浏览器地址栏和其他浏览器的控制选项。与Web应用相比,Web部分打包在应用内部,使用时不需要网络,(通过AppCache)。

一些框架(Framework),比如Cordova,PhoneGap 或Titanium都提供了易用的模板,供Javascript访问原生移动系统API。 PhoneGap的主要作用是让JavaScript可以调用设备功能,也包括调用原生代码。使用PhoneGap,可以使用Web技术来开发APP,无需使用Java或Objective C。

关注 28 回答 16

honglio 回答了问题 · 2015-11-18

解决android webview 不支持css3 flex布局 怎么办?

android 4.4以上版本支持display:flex。低版本不支持。

关注 6 回答 3

honglio 回答了问题 · 2015-11-18

jsHint不检查语句块后面的分号怎么设置?

在.jshintrc里加入asi: false将不检查语句后面的分号。

关注 3 回答 2

honglio 赞了文章 · 2015-10-27

Android Hybrid App四大坑

首发我的博客:Android Hybrid App四大坑

首先解释下题目,Hybrid App,混合应用,代表平台PhoneGap,一般指使用原生包装Web页面开发的应用。与原生应用相比,主要用户界面和业务逻辑都是用Web技术也就是HTML+CSS+Javascript实现的;与Web应用相比,Web部分打包在应用内部,使用时不需要网络。

顺便说一句,很多解决方案其实不算Hybrid,比如Adobe AIRTitaniumMono,这些都是使用某一特定技术开发跨平台应用的工具,最终产品都是编译成原生来跑的。

我们没有选择PhoenGap为技术基础(我对此并不满意,我认为以PhoneGap为基础可以少走一些弯路,少花一些精力,还能产出很多有价值的副产品),而是自行开发原生框架,主要目标平台是Android——嗯,就是那个从系统版本到模块组合都巨分散的Android,可以这么说,坎坷从立项的那一刻起就已经注定了……接下来,便请听我一一讲述:Android Hybrid App四大坑。(此文主要针对Android 4.3及之前的webview,部分浏览器比如Chrome已经改善了具体实现,所以Web App其实环境不错。)

游戏泡泡v0.2首页截图

前端代码开源就好,https://github.com/Dianjoy/gamepop,要跑起来需要修改config.js,把if (debug) {}的内容删掉。

缺少标准flexbox

Flexbox是CSS3里面一项非常重要的改进,大大改善了布局工作。可惜从草案到终案时间跨度太长,于是市面上绝大部分设备只支持display:-webkit-box。这给上图中图标区域的布局带来了难处,最终只能混合使用两种布局,display:inline-blockdisplay:flex。需要注意,inline-block元素之间,如果在代码中有空格换行符的话,渲染时会有约0.25em~0.5em大小的间隙,所以想一行4列每列width:25%的话会放不下导致折行。开始我在其父元素中设置font:0/0 a,大部分手机都OK,中兴ZTE795就不行,擦,上次也是它……后来我索性把所有空格和换行符都干掉,终于OK了。

这段代码演示inline-block布局时父元素字体对子元素之间间歇的影响。

<iframe data-original="http://jsfiddle.net/meathill/9Uk5Y/embedded/result,html,css,js/presentation/" height="200" width="100%" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

所以,对于多行多列的grid布局,我们要谨记:

对父元素使用display:flex;flex-direction: row;flex-wrap: wrap;在现代浏览器和Android4.4以上的系统中,可以取得完美表现。
使用display:inline-block;box-sizing: border-box;vertical-align: top;,并且在代码中移除块与块之间的空白字符,避免换行,保留合适的边距。
遗憾的是,低版本的webview中,高度不会自适应,除非使用js进行计算,不然还是尽量避免在元素下方画线的举动。

tap vs click

(这个问题简直令人发指。)我们知道,很多浏览器默认行为都依赖click事件触发,比如超链接、input[type=radio]的选中,等等。在4.4之前的webview中,click比真实操作延迟约300ms触发,会带给用户明显的延滞感。为了提升用户体验,我们多数使用tap事件部分替代click事件,以便及时响应用户操作。可选方案很多,Hammer.jsFastclick,甚至Zepto都有封装。

于是新的问题出现了。比如我们用<a>实现了一个删除按钮,tap时,删除当前元素,并且将按钮重置为下载按钮,href为下载的url。用PC开发时一切正常,但到真机测试就会发现,因为tap是即时的,新按钮立刻替换了旧按钮,300ms后,click事件在新按钮上触发了,结果又开始下载……再比如,图层中有个后退按钮,点击后,图层移除,露出下面覆盖的部分,如果在tap的位置上刚好有一枚链接,此时就会触发click,页面跳转……以及,上次总结说的下载链接不触发click,问题也一样,只不过翻过来,click该触发的时候,被图层挡住了,所以没有触发。

展现误触click的bug的原理

解决方案基本围绕“如何熬过300ms”,和“甄别事件对象”来设计。

还是上面两个场景,第一个,按下之后,setTimeout 400ms(以防万一)后再替换按钮;第二个,给图层加一个消失的动画,持续400ms,保证click触发时图层还在。可能大家有疑问,为何不干脆禁掉click事件,前面说了,很多浏览器默认行为依赖click事件,禁掉之后又会引发别的问题。

另一个解决方案是甄别事件对象,在用户touchstart的时候,记下event.target,等到click触发时,对比,如果不一致则认为是抽风,event.preventDefault()。我更推荐这种做法,毕竟400ms也不算短。不过要注意,<label>在响应click时,会自动触发它for的元素的click,所以要用新增的control属性进行二次对比,以免误伤。

position:relative;竟然抢事件

这个问题解决起来容易,排查时没少花时间。表现为,一个按钮,就在那里,但怎么点都没用。后来只好追踪全局事件,发现事件的对象并非按钮,而是按钮下面被遮盖的层。很奇怪,我知道translateZ可能导致这个问题,不过现在完全没用到;而且下面的图层实际并没有那么长(参照上图中,内容列表和下面的三个按钮,就是那里),列表的底部是bottom:60px,刚好应该把<footer>的三个按钮空出来。

然后我开始怀疑position:relative;,因为只有这个东西会影响布局。把它点掉后,按钮果然可以点了,于是我给<footer>也加上了position:relative;问题就这样解决了。我觉得这肯定又是个Android Webview的Bug,因为我并没有给下面层里的元素设置z-index,只有position:relative。总之,如果按钮点击没反应,尽早看看事件对象是哪个,说不定被哪个层抢走了。

各种待实现的API

caniuse.com是个神器,我在使用某个API或者CSS属性时不太有把握的话,都会去查一下。然而,谁又知道Android Webview默认很多API都没开呢?大到localStorage,小到alertconfirm,都需要主动开放,不然就没法用。测试的时候又很难查,原生的环境多不在我这儿,配也不太容易,大家的习惯都不一致,只能等对方反馈过来错误信息,我到代码里查,但常常死活看不出来哪儿有问题。

后来认清现实就好办,Android Webview其实是个半残废,有不明白的问题,多半是API实现不全导致的。最简单的办法是用modernizr之类的工具进行特性检测,或者在Weinre、Adobe Inspect CC里直接敲API。总之,别怀疑自己,基本都是Android Webview的问题。

这也是我为什么希望以PhoneGap为基础的原因:PhoneGap已经按照规范实现了大部分API。插件库也很丰富,比如GA——说到这个,我们想实现一个简单的统计,因为老板嫌GA太大,所以干脆使用同样的接口,只请求一下我们的日志服务器,留下条日志就好,结果我们惊讶地发现:Android里原生给Webview环境增加API,方法的参数不能多也不能少,不然就报错,真奇葩——可以省下很多时间。产出的结果,还可以分享到社区一部分,对于我们公司,也能增加了不少开发者资源。

总结

早先别人鄙视Hybrid App的时候我也各种不服,心说“你们丫懂毛啊就指手画脚的说不行”;现在经历了各种大坑小坑连环坑之后,我的想法已经变成了“你们丫懂毛啊不就是一不小心蒙对了么”。

Hybrid App开发会遭遇比原生和Web App更多的坎坷,这我有心理准备;如此多的坑无形中也在提升我的个人价值,我对此甚至隐隐有些高兴。不过我还是希望这段混乱之治尽快过去,Android平台不要再分裂了,高版本系统尽快普及,所有前端开发的日子都会好过许多。

现在,如果可能的话,尽量以PhoneGap为基础进行开发,能省很多时间和精力。对于前端人来说,更是能把测试环境搬到本地,实在是非常大的帮助。

Android 4.4时再次分裂,之后使用blink作为webview的基础;之前则是webkit,前者无论CSS还是API都有更佳表现,Nexus 5基本没怎么改就都测试通过了。所以将来老罗的锤子手机开卖我一定买一台支持他,因为他良心的采用4.4为基础,对前端真是个难得的好消息。

查看原文

赞 15 收藏 56 评论 17

honglio 赞了问题 · 2015-10-27

解决不使用jQuery只用js+css如何实现带百分比的环形进度条?

环形进度条在网上很多都是基于jQuery实现的,如果在不使用jQuery的情况下,仅用js+css如何实现环形进度条呢?

关注 4 回答 2

honglio 赞了回答 · 2015-10-27

解决不使用jQuery只用js+css如何实现带百分比的环形进度条?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
    body {
            font-family: "微软雅黑";
        }
        .circle {
            width: 200px;
            height: 200px;
            position: absolute;
            border-radius: 50%;
            background: #0cc;
        }
        .pie_left, .pie_right {
            width:200px; 
            height:200px;
            position: absolute;
            top: 0;left: 0;
        }
        .left, .right {
            width:200px; 
            height:200px;
            background:#00aacc;
            border-radius: 50%;
            position: absolute;
            top: 0;
            left: 0;
        }
        .pie_right, .right {
            clip:rect(0,auto,auto,100px);
        }
        .pie_left, .left {
            clip:rect(0,100px,auto,0);
        }
        .mask {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            left: 25px;
            top: 25px;
            background: #FFF;
            position: absolute;
            text-align: center;
            line-height: 150px;
            font-size: 20px;
            font-weight: bold;
            color: #00aacc;
        }
    </style>
    
</head>
<body>
    <div class="circle" style="left:0">
        <div class="pie_left"><div class="left"></div></div>
        <div class="pie_right"><div class="right"></div></div>
        <div class="mask"><span>0</span>%</div>
    </div>
    
    <script type="text/javascript">
        //addPercent(30);
        function addPercent(num){
          if(num>100)return;
          var c=document.getElementsByClassName("circle")[0];
          c.getElementsByTagName("span")[0].innerHTML=num;
          num=num*3.6;
          if(num<=180){
            c.getElementsByClassName("right")[0].style.transform="rotate(" + num + "deg)";
          }else{
            c.getElementsByClassName("right")[0].style.transform="rotate(180deg)";
            c.getElementsByClassName("left")[0].style.transform="rotate(" + (num - 180) + "deg)";
          }
          
        }
        
        var count=0;
        var t=setInterval(function(){
          if(count>100){
            clearInterval(t);
          }
          addPercent(++count);
        },200);
    </script>
</body>
</html>

这个随便找个就能翻译成js的。。还有就是我简单翻译了一下没有封装,没有管怎么调用

关注 4 回答 2

认证与成就

  • 获得 31 次点赞
  • 获得 27 枚徽章 获得 2 枚金徽章, 获得 11 枚银徽章, 获得 14 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2012-10-05
个人主页被 826 人浏览