zoukankan      html  css  js  c++  java
  • 【iScroll源码学习00】模拟iScroll

    【iScroll源码学习00】模拟iScroll

    前言

    相信对移动端有了解的朋友对iScroll这个库非常熟悉吧,今天我们就来说下我们移动页面的iScroll化

    iScroll是我们必学框架之一,我们这次先根据iScroll功能自己实现其功能,然后再学习iScroll源码

    下面先给出iScroll官方的例子和源码,要看效果的朋友自己去看吧:https://github.com/cubiq/iscroll

    本人能力有限,文中有误请提出

    viewport

    在移动端新出了一个属性叫做“viewport”,这个便是我们手机上的虚拟视口(viewport),也就是视觉窗口,显示区域

    移动设备的显示区域比电脑小得多(但也方便得多),为了让手机显示的更加友好,Apple提供了一个方法:在浏览器定义了viewport meta标签

    他的作用就是创建一个虚拟窗口,这个虚拟窗口接近桌面浏览器(980px),事实上viewport就是用以放大缩小网页内容

    复制代码
    <meta name=”viewport” 
    content=”width=device-width, initial-scale=1, maximum-scale=1″>
    
    width:控制 viewport 的大小,可以指定的一个值,如果 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
    height:和 width 相对应,指定高度。
    initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
    maximum-scale:允许用户缩放到的最大比例。
    minimum-scale:允许用户缩放到的最小比例。
    user-scalable:用户是否可以手动缩放
    复制代码

    visual/layout viewport

    (此处引用——原文出处: quirksmode   译文出处: Zhao Yuhao

    想象我们有个房间,我们可以控制房间大小,现在我们站在他窗户面前,正对着窗户的墙壁涂满了壁画,我们走到窗口一米的位置往房间看(假设房子很大)

    我们能看到整个壁画,但是有点小,于是我们缩小房子就能看清细节了,这里的窗户就是visual viewport 墙壁就是layout viewport

    对于css布局,特别是用宽度百分比做排版时候,比率是按照layout viewport计算,也就是说一个div相对宽度50%,用户在手机浏览器放大缩小

    div宽度不会一直显示相对窗口50%,整个div可能铺满窗口小到看不到

    我们这里的viewport就相当于放大和缩小房间,找到一个合适的平衡点,让我们的网页在手机上更友好的显示

    ① 假如我们现在又个简单的页面,不给div设置宽度(默认是layout100%——980px),所以显示效果为:

    ② 用户通过放大网页比例,缩小visual viewport的值,相对而言用户就能看清楚div的内容了,但是layout viewport本身未发现变化(所以可能出现滚动条)

    ③ 这个时候上文中的device-width就派上了用场,他可以将layout viewport的像素设置为设备的像素,这样的话:

    visual viewport=layout viewport=screen width,这个体验就比较好了

    device-width

    以上知识点暂时到这,这里我们补充几个知识点:

    ① 宽度问题:

    layout viewport 的长宽 (document.documentElement.clientWidth / document.documentElement.clientHeight)
    
    visual viewport 的长宽 (window.innerWidth / window.innerHeight)

    ② 设备像素

    screen.width/height

    ③ Media queries,这个是html5新增特性,可以根据device-width(设备宽度,screen width)来确定显示不同的CSS

    1. visual viewport 宽度 : 默认980 实际大小与缩放比例相关,可以通过meta的viewport属性修改
    2. layout viewport 宽度 : 980 
    3. screen.width         :320

    我们这里来重新理解下device-width这个属性,这里提供一段代码,两个截图:

    View Code
    <meta name="viewport" content="width=100">
    <!-- 这里以此给width赋值:① 默认情况/② device-width/③ 100 ->

    为何出现iScroll

    fixed与噩梦

    最初的ios与android并不支持fixed属性,因为我们的手机有一个叫viewport的东西这个大家都知道了,fixed位置是相对整个页面的固定位置

    页面中的页面没什么变化,只不过在viewport下变大了,而且我们移动的是viewport,网页并未跟着滚动,于是我们移动的事实上是viewport,

    而我们viewport移动并不会让我们fixed元素跟着变化,因为他是相对于手机屏幕的,所以就不支持了,反正后面这个问题被修复了

    但是据我的经验来说,就是现在ios6、7或者android高版本fixed仍然不是那么好使,移动端的fixed就跟ie7的float似的,让人想哭

    特别是当你点击文本框时候看到键盘上来了,页面错位了,一股想扔手机之情油然而生

    加之想要用户自动升级手机浏览器什么的仍然不现实,所以iScroll诞生了,这是iScroll诞生的主要原因(我是这么认为的)

    overflow: auto

    既然fixed不好使,那么就头尾固定,中间body部分使用overflow属性吧,但是可恨的是overflow属性仍然不好使!!!

    我们这里来做一个demo:

    View Code

    其实这个属性也是可以实现三行布局的基本功能的,但是有以下几个问题:

    ① 没有滚动条

    ② 滚动不顺畅

    ③ 手机浏览器支持良莠不齐

    但是这些缺点也不能掩盖他最大的优点:原生性!!!原生的就是最好的,如果哪天这个属性升级的话,前途就好了

    页面切换动画

    要伪装APP,页面切换动画必不可少,但是如果中间部分不固定的话就会碰到另外一个令人头疼的问题:

    长短页切换问题,想象下几个长短不一的页面切换会有多丑呢???

    PS:这也是我现在遇到的问题

    基于以上原因,所以出现了iScroll这样的实用库,当然,以上只是个人猜想......

    实现iScroll功能

    基本dom结构

    以上扯了那么多,与本文的最初目的关系其实不大,我们的主要目的还是得先实现一个简单的iScroll功能才行(依赖zepto)

    复制代码
     1 <html xmlns="http://www.w3.org/1999/xhtml">
     2 <head>
     3   <title></title>
     4   <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
     5   <style type="text/css">
     6     body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { margin: 0; padding: 0; }
     7     body { font: normal 14px/1.5 "Arial" , "Lucida Grande" ,Verdana, "Microsoft YaHei" , "hei"; -webkit-font-smoothing: antialiased; color: #000; background: #f5f5f5; }
     8     header { position: absolute; top: 0; left: 0; width: 100%; height: 48px; background-color: #1491c5; }
     9     footer { position: absolute; bottom: 0; left: 0; width: 100%; height: 48px; background-color: #1491c5; }
    10     h1 { display: block; font-size: 2em; font-weight: bold; font-weight: 500; text-align: center; color: White; }
    11     #body { background: #fff; border: 1px solid #cfcfcf; width: 96%; height: 100%; margin: 50px auto; padding: 4px; }
    12   </style>
    13 </head>
    14 <body>
    15   <header id="header">
    16     <h1>
    17       Header</h1>
    18   </header>
    19   <div id="body">
    20     body
    21   </div>
    22   <footer>
    23     <h1>
    24       Footer</h1>
    25   </footer>
    26 </body>
    27 </html>
    复制代码

    我们根据iScroll的动作先写下以下代码:

    View Code

    http://sandbox.runjs.cn/show/oztjkadg(最好使用手机访问)

    事件绑定

    样式出来了,我们现在就该注册事件了,支持touch就是要touch,否则就是要mouse事件了:

    View Code

    这个是我们第一步形成的代码,他具有以下问题待解决:

    ① 由于是CSS3实现的动画,不能保存状态,所以我们再次点击时候不能停止动画

    ② 未使用CSS3的transform,所以整个功能暂不支持3D加速

    ③ 由于touch时候的e.preventDefault,所以其中的文本框等在手机上不能获取焦点

    以上焦点便是我们接下来需要解决的地方,上面提出了三大问题,我们这里来一一解决

    硬件加速

    各位看到上面实现动画的方法是通过变化元素的Top实现的,这样做原来有一个好处就是可以向下兼容,但是对于移动端来说意义不大

    事实上这里的top实现动画变为translate实现动画更为舒服,原因是手机对CSS3动画做了处理,可以开启硬件加速

    我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能

    CSS animations, transforms 以及 transitions 不会自动开启GPU加速,而是由浏览器的缓慢的软件渲染引擎来执行。

    .cube {
       -webkit-transform: translate3d(250px,250px,250px)
       rotate3d(250px,250px,250px,-120deg)
       scale3d(0.5, 0.5, 0.5);
    }

    以上代码便会开启硬件加速,所以我们这里的对应关系是这样的:

    top=>translate3d(0, 0, 0)

    加速是好的,滥用可能引起性能问题,而且ios下动画可能产生抖动现象,这个各位一定要注意,于是通过这个,我们修改我们的代码:

    http://sandbox.runjs.cn/show/wqw1lpcl(请用webkit手机对比)

    View Code

    PS:对比下来,我想说,硬件加速的感觉真他妈爽!!!!这段代码没有过多测试,有问题请留言 

    停止CSS动画

    要停止CSS动画,并且要保存CSS的状态,这个问题其实在三个问题中,我认为是最难的,因为我们可能遇到如下需求:

    ① 移动过程手指触摸屏幕,动画停止

    ② 连续滑动时候需要动画加速

    如何停止CSS3的动画?

    我这里自然处理不到这么复杂的问题,所以就先实现停止动画即可

    <div id="wrapper" style="position: absolute; -webkit-transform: translate3d(0px, -558px, 0px);
      -webkit-transition: -webkit-transform 20.1s linear; transition: -webkit-transform 20.1s linear;">
    </div>

    这个就是zepto一次动画获得的参数,我故意将时间设置的很长,我们要在点击时候马上获取transform,并且重新设置

    http://sandbox.runjs.cn/show/vgekfj8f

    View Code

    PS:时间比较晚了,代码未做检测,各位包含 

    文本获取焦点

    由于e.preventDefault的效果,所以我们里面的按钮点击一键文本框获取焦点有点不好使,我这里主要解决文本获取焦点即可

    我们在touchstart时候可以获取e.target,在touchend时候若是判断是一次点击事件并且target为文本框的话,便获取焦点。

    PS:我这里因为暂时不用作生产,先简单实现即可

    http://sandbox.runjs.cn/show/djkrwwno

    View Code

    如此,文本类标签便可以获得焦点了,其它的东西,各位通过代码自己搞下吧,现在只剩下停止动画了......有点累

    核心代码:

    复制代码
     1 if (this._needFocus(this.clickEl)) {
     2   $(this.clickEl).focus();
     3   return;
     4 }
     5 _needFocus: function (el) {
     6   switch (el.nodeName.toLowerCase()) {
     7     case 'textarea':
     8     case 'select':
     9       return true;
    10     case 'input':
    11       switch (el.type) {
    12         case 'button':
    13         case 'checkbox':
    14         case 'file':
    15         case 'image':
    16         case 'radio':
    17         case 'submit':
    18           return false;
    19       }
    20       return !el.disabled && !el.readOnly;
    21     default:
    22       return (/needfocus/).test(el.className);
    23   }
    24 },
    复制代码

    结语

    今天,我们一起实现了简单的iScroll的功能,明天我们一起来进行源码学习,看看iScroll到底有何优点

    如果您发现文中有何问题,请与我联系。

  • 相关阅读:
    Centos7.6部署rsyslog+loganalyzer+mysql日志管理服务器
    linux编程基础
    天融信防火墙NGFW4000,无法进入web管理和community属性查看
    H3C_IRF_BFD配置
    H3C_IRF_LACP配置
    H3C_IRF
    h3c_7506e引擎主备镜像同步
    cisco4507引擎模式切换
    usg6000
    vpdn1
  • 原文地址:https://www.cnblogs.com/xuqiudong/p/4773207.html
Copyright © 2011-2022 走看看